Unified · Split
| @@ -17,10 +17,12 @@ HCI · 16 unmodified lines | ||
| 17 | 17 | HCI registers as an nfc device with NFC Core. Requests coming from userspace are |
| 18 | 18 | routed through netlink sockets to NFC Core and then to HCI. From this point, |
| 19 | 19 | they are translated in a sequence of HCI commands sent to the HCI layer in the |
| 20 | −host controller (the chip). The sending context blocks while waiting for the | |
| 21 | −response to arrive. | |
| 20 | +host controller (the chip). Commands can be executed synchronously (the sending | |
| 21 | +context blocks waiting for response) or asynchronously (the response is returned | |
| 22 | +from HCI Rx context). | |
| 22 | 23 | HCI events can also be received from the host controller. They will be handled |
| 23 | −and a translation will be forwarded to NFC Core as needed. | |
| 24 | +and a translation will be forwarded to NFC Core as needed. There are hooks to | |
| 25 | +let the HCI driver handle proprietary events or override standard behavior. | |
| 24 | 26 | HCI uses 2 execution contexts: |
| 25 | 27 | - one for executing commands : nfc_hci_msg_tx_work(). Only one command |
| 26 | 28 | can be executing at any given moment. |
| @@ -33,6 +35,8 @@ The Session initialization is an HCI standard which must unfortunately · 6 unmodified lines | ||
| 33 | 35 | support proprietary gates. This is the reason why the driver will pass a list |
| 34 | 36 | of proprietary gates that must be part of the session. HCI will ensure all |
| 35 | 37 | those gates have pipes connected when the hci device is set up. |
| 38 | +In case the chip supports pre-opened gates and pseudo-static pipes, the driver | |
| 39 | +can pass that information to HCI core. | |
| 36 | 40 | |
| 37 | 41 | HCI Gates and Pipes |
| 38 | 42 | ------------------- |
| @@ -46,6 +50,13 @@ without knowing the pipe connected to it. · 7 unmodified lines | ||
| 46 | 50 | Driver interface |
| 47 | 51 | ---------------- |
| 48 | 52 | |
| 53 | +A driver is generally written in two parts : the physical link management and | |
| 54 | +the HCI management. This makes it easier to maintain a driver for a chip that | |
| 55 | +can be connected using various phy (i2c, spi, ...) | |
| 56 | + | |
| 57 | +HCI Management | |
| 58 | +-------------- | |
| 59 | + | |
| 49 | 60 | A driver would normally register itself with HCI and provide the following |
| 50 | 61 | entry points: |
| 51 | 62 | |
| @@ -53,58 +64,113 @@ struct nfc_hci_ops { · 1 unmodified line | ||
| 53 | 64 | int (*open)(struct nfc_hci_dev *hdev); |
| 54 | 65 | void (*close)(struct nfc_hci_dev *hdev); |
| 55 | 66 | int (*hci_ready) (struct nfc_hci_dev *hdev); |
| 56 | − int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb); | |
| 57 | − int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols); | |
| 58 | − int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate, | |
| 59 | − struct nfc_target *target); | |
| 67 | + int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb); | |
| 68 | + int (*start_poll) (struct nfc_hci_dev *hdev, | |
| 69 | + u32 im_protocols, u32 tm_protocols); | |
| 70 | + int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target, | |
| 71 | + u8 comm_mode, u8 *gb, size_t gb_len); | |
| 72 | + int (*dep_link_down)(struct nfc_hci_dev *hdev); | |
| 73 | + int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate, | |
| 74 | + struct nfc_target *target); | |
| 60 | 75 | int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate, |
| 61 | 76 | struct nfc_target *target); |
| 62 | − int (*data_exchange) (struct nfc_hci_dev *hdev, | |
| 63 | − struct nfc_target *target, | |
| 64 | − struct sk_buff *skb, struct sk_buff **res_skb); | |
| 77 | + int (*im_transceive) (struct nfc_hci_dev *hdev, | |
| 78 | + struct nfc_target *target, struct sk_buff *skb, | |
| 79 | + data_exchange_cb_t cb, void *cb_context); | |
| 80 | + int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb); | |
| 65 | 81 | int (*check_presence)(struct nfc_hci_dev *hdev, |
| 66 | 82 | struct nfc_target *target); |
| 83 | + int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event, | |
| 84 | + struct sk_buff *skb); | |
| 67 | 85 | }; |
| 68 | 86 | |
| 69 | 87 | - open() and close() shall turn the hardware on and off. |
| 70 | 88 | - hci_ready() is an optional entry point that is called right after the hci |
| 71 | 89 | session has been set up. The driver can use it to do additional initialization |
| 72 | 90 | that must be performed using HCI commands. |
| 73 | −- xmit() shall simply write a frame to the chip. | |
| 91 | +- xmit() shall simply write a frame to the physical link. | |
| 74 | 92 | - start_poll() is an optional entrypoint that shall set the hardware in polling |
| 75 | 93 | mode. This must be implemented only if the hardware uses proprietary gates or a |
| 76 | 94 | mechanism slightly different from the HCI standard. |
| 95 | +- dep_link_up() is called after a p2p target has been detected, to finish | |
| 96 | +the p2p connection setup with hardware parameters that need to be passed back | |
| 97 | +to nfc core. | |
| 98 | +- dep_link_down() is called to bring the p2p link down. | |
| 77 | 99 | - target_from_gate() is an optional entrypoint to return the nfc protocols |
| 78 | 100 | corresponding to a proprietary gate. |
| 79 | 101 | - complete_target_discovered() is an optional entry point to let the driver |
| 80 | 102 | perform additional proprietary processing necessary to auto activate the |
| 81 | 103 | discovered target. |
| 82 | −- data_exchange() must be implemented by the driver if proprietary HCI commands | |
| 104 | +- im_transceive() must be implemented by the driver if proprietary HCI commands | |
| 83 | 105 | are required to send data to the tag. Some tag types will require custom |
| 84 | 106 | commands, others can be written to using the standard HCI commands. The driver |
| 85 | 107 | can check the tag type and either do proprietary processing, or return 1 to ask |
| 86 | −for standard processing. | |
| 108 | +for standard processing. The data exchange command itself must be sent | |
| 109 | +asynchronously. | |
| 110 | +- tm_send() is called to send data in the case of a p2p connection | |
| 87 | 111 | - check_presence() is an optional entry point that will be called regularly |
| 88 | 112 | by the core to check that an activated tag is still in the field. If this is |
| 89 | 113 | not implemented, the core will not be able to push tag_lost events to the user |
| 90 | 114 | space |
| 115 | +- event_received() is called to handle an event coming from the chip. Driver | |
| 116 | +can handle the event or return 1 to let HCI attempt standard processing. | |
| 91 | 117 | |
| 92 | 118 | On the rx path, the driver is responsible to push incoming HCP frames to HCI |
| 93 | 119 | using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling |
| 94 | 120 | This must be done from a context that can sleep. |
| 95 | 121 | |
| 96 | −SHDLC | |
| 97 | −----- | |
| 122 | +PHY Management | |
| 123 | +-------------- | |
| 124 | + | |
| 125 | +The physical link (i2c, ...) management is defined by the following struture: | |
| 126 | + | |
| 127 | +struct nfc_phy_ops { | |
| 128 | + int (*write)(void *dev_id, struct sk_buff *skb); | |
| 129 | + int (*enable)(void *dev_id); | |
| 130 | + void (*disable)(void *dev_id); | |
| 131 | +}; | |
| 132 | + | |
| 133 | +enable(): turn the phy on (power on), make it ready to transfer data | |
| 134 | +disable(): turn the phy off | |
| 135 | +write(): Send a data frame to the chip. Note that to enable higher | |
| 136 | +layers such as an llc to store the frame for re-emission, this function must | |
| 137 | +not alter the skb. It must also not return a positive result (return 0 for | |
| 138 | +success, negative for failure). | |
| 139 | + | |
| 140 | +Data coming from the chip shall be sent directly to nfc_hci_recv_frame(). | |
| 141 | + | |
| 142 | +LLC | |
| 143 | +--- | |
| 144 | + | |
| 145 | +Communication between the CPU and the chip often requires some link layer | |
| 146 | +protocol. Those are isolated as modules managed by the HCI layer. There are | |
| 147 | +currently two modules : nop (raw transfert) and shdlc. | |
| 148 | +A new llc must implement the following functions: | |
| 149 | + | |
| 150 | +struct nfc_llc_ops { | |
| 151 | + void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, | |
| 152 | + rcv_to_hci_t rcv_to_hci, int tx_headroom, | |
| 153 | + int tx_tailroom, int *rx_headroom, int *rx_tailroom, | |
| 154 | + llc_failure_t llc_failure); | |
| 155 | + void (*deinit) (struct nfc_llc *llc); | |
| 156 | + int (*start) (struct nfc_llc *llc); | |
| 157 | + int (*stop) (struct nfc_llc *llc); | |
| 158 | + void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb); | |
| 159 | + int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb); | |
| 160 | +}; | |
| 161 | + | |
| 162 | +- init() : allocate and init your private storage | |
| 163 | +- deinit() : cleanup | |
| 164 | +- start() : establish the logical connection | |
| 165 | +- stop () : terminate the logical connection | |
| 166 | +- rcv_from_drv() : handle data coming from the chip, going to HCI | |
| 167 | +- xmit_from_hci() : handle data sent by HCI, going to the chip | |
| 98 | 168 | |
| 99 | −Most chips use shdlc to ensure integrity and delivery ordering of the HCP | |
| 100 | −frames between the host controller (the chip) and hosts (entities connected | |
| 101 | −to the chip, like the cpu). In order to simplify writing the driver, an shdlc | |
| 102 | −layer is available for use by the driver. | |
| 103 | −When used, the driver actually registers with shdlc, and shdlc will register | |
| 104 | −with HCI. HCI sees shdlc as the driver and thus send its HCP frames | |
| 105 | −through shdlc->xmit. | |
| 106 | −SHDLC adds a new execution context (nfc_shdlc_sm_work()) to run its state | |
| 107 | −machine and handle both its rx and tx path. | |
| 169 | +The llc must be registered with nfc before it can be used. Do that by | |
| 170 | +calling nfc_llc_register(const char *name, struct nfc_llc_ops *ops); | |
| 171 | + | |
| 172 | +Again, note that the llc does not handle the physical link. It is thus very | |
| 173 | +easy to mix any physical link with any llc for a given chip driver. | |
| 108 | 174 | |
| 109 | 175 | Included Drivers |
| 110 | 176 | ---------------- |
| @@ -117,10 +183,12 @@ Execution Contexts · 6 unmodified lines | ||
| 117 | 183 | |
| 118 | 184 | The execution contexts are the following: |
| 119 | 185 | - IRQ handler (IRQH): |
| 120 | −fast, cannot sleep. stores incoming frames into an shdlc rx queue | |
| 186 | +fast, cannot sleep. sends incoming frames to HCI where they are passed to | |
| 187 | +the current llc. In case of shdlc, the frame is queued in shdlc rx queue. | |
| 121 | 188 | |
| 122 | 189 | - SHDLC State Machine worker (SMW) |
| 123 | −handles shdlc rx & tx queues. Dispatches HCI cmd responses. | |
| 190 | +Only when llc_shdlc is used: handles shdlc rx & tx queues. | |
| 191 | +Dispatches HCI cmd responses. | |
| 124 | 192 | |
| 125 | 193 | - HCI Tx Cmd worker (MSGTXWQ) |
| 126 | 194 | Serializes execution of HCI commands. Completes execution in case of response |
| @@ -166,6 +234,15 @@ waiting command execution. Response processing involves invoking the completion · 39 unmodified lines | ||
| 166 | 234 | callback that was provided by nfc_hci_msg_tx_work() when it sent the command. |
| 167 | 235 | The completion callback will then wake the syscall context. |
| 168 | 236 | |
| 237 | +It is also possible to execute the command asynchronously using this API: | |
| 238 | + | |
| 239 | +static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, | |
| 240 | + const u8 *param, size_t param_len, | |
| 241 | + data_exchange_cb_t cb, void *cb_context) | |
| 242 | + | |
| 243 | +The workflow is the same, except that the API call returns immediately, and | |
| 244 | +the callback will be called with the result from the SMW context. | |
| 245 | + | |
| 169 | 246 | Workflow receiving an HCI event or command |
| 170 | 247 | ------------------------------------------ |
| 171 | 248 | |
| @@ -1,32 +1,15 @@ | ||
| 1 | 1 | Kernel driver for the NXP Semiconductors PN544 Near Field |
| 2 | 2 | Communication chip |
| 3 | 3 | |
| 4 | −Author: Jari Vanhala | |
| 5 | −Contact: Matti Aaltonen (matti.j.aaltonen at nokia.com) | |
| 6 | − | |
| 7 | 4 | General |
| 8 | 5 | ------- |
| 9 | 6 | |
| 10 | 7 | The PN544 is an integrated transmission module for contactless |
| 11 | 8 | communication. The driver goes under drives/nfc/ and is compiled as a |
| 12 | −module named "pn544". It registers a misc device and creates a device | |
| 13 | −file named "/dev/pn544". | |
| 9 | +module named "pn544". | |
| 14 | 10 | |
| 15 | 11 | Host Interfaces: I2C, SPI and HSU, this driver supports currently only I2C. |
| 16 | 12 | |
| 17 | −The Interface | |
| 18 | −------------- | |
| 19 | − | |
| 20 | −The driver offers a sysfs interface for a hardware test and an IOCTL | |
| 21 | −interface for selecting between two operating modes. There are read, | |
| 22 | −write and poll functions for transferring messages. The two operating | |
| 23 | −modes are the normal (HCI) mode and the firmware update mode. | |
| 24 | − | |
| 25 | −PN544 is controlled by sending messages from the userspace to the | |
| 26 | −chip. The main function of the driver is just to pass those messages | |
| 27 | −without caring about the message content. | |
| 28 | − | |
| 29 | − | |
| 30 | 13 | Protocols |
| 31 | 14 | --------- |
| 32 | 15 | |
| @@ -47,68 +30,3 @@ and third (LSB) bytes of the message. The maximum FW message length is · 14 unmodified lines | ||
| 47 | 30 | |
| 48 | 31 | For the ETSI HCI specification see |
| 49 | 32 | http://www.etsi.org/WebSite/Technologies/ProtocolSpecification.aspx |
| 50 | − | |
| 51 | −The Hardware Test | |
| 52 | −----------------- | |
| 53 | − | |
| 54 | −The idea of the test is that it can performed by reading from the | |
| 55 | −corresponding sysfs file. The test is implemented in the board file | |
| 56 | −and it should test that PN544 can be put into the firmware update | |
| 57 | −mode. If the test is not implemented the sysfs file does not get | |
| 58 | −created. | |
| 59 | − | |
| 60 | −Example: | |
| 61 | −> cat /sys/module/pn544/drivers/i2c\:pn544/3-002b/nfc_test | |
| 62 | −1 | |
| 63 | − | |
| 64 | −Normal Operation | |
| 65 | −---------------- | |
| 66 | − | |
| 67 | −PN544 is powered up when the device file is opened, otherwise it's | |
| 68 | −turned off. Only one instance can use the device at a time. | |
| 69 | − | |
| 70 | −Userspace applications control PN544 with HCI messages. The hardware | |
| 71 | −sends an interrupt when data is available for reading. Data is | |
| 72 | −physically read when the read function is called by a userspace | |
| 73 | −application. Poll() checks the read interrupt state. Configuration and | |
| 74 | −self testing are also done from the userspace using read and write. | |
| 75 | − | |
| 76 | −Example platform data: | |
| 77 | − | |
| 78 | −static int rx71_pn544_nfc_request_resources(struct i2c_client *client) | |
| 79 | −{ | |
| 80 | − /* Get and setup the HW resources for the device */ | |
| 81 | −} | |
| 82 | − | |
| 83 | −static void rx71_pn544_nfc_free_resources(void) | |
| 84 | −{ | |
| 85 | − /* Release the HW resources */ | |
| 86 | −} | |
| 87 | − | |
| 88 | −static void rx71_pn544_nfc_enable(int fw) | |
| 89 | −{ | |
| 90 | − /* Turn the device on */ | |
| 91 | −} | |
| 92 | − | |
| 93 | −static int rx71_pn544_nfc_test(void) | |
| 94 | −{ | |
| 95 | − /* | |
| 96 | − * Put the device into the FW update mode | |
| 97 | − * and then back to the normal mode. | |
| 98 | − * Check the behavior and return one on success, | |
| 99 | − * zero on failure. | |
| 100 | − */ | |
| 101 | −} | |
| 102 | − | |
| 103 | −static void rx71_pn544_nfc_disable(void) | |
| 104 | −{ | |
| 105 | − /* turn the power off */ | |
| 106 | −} | |
| 107 | − | |
| 108 | −static struct pn544_nfc_platform_data rx71_nfc_data = { | |
| 109 | − .request_resources = rx71_pn544_nfc_request_resources, | |
| 110 | − .free_resources = rx71_pn544_nfc_free_resources, | |
| 111 | − .enable = rx71_pn544_nfc_enable, | |
| 112 | − .test = rx71_pn544_nfc_test, | |
| 113 | − .disable = rx71_pn544_nfc_disable, | |
| 114 | −}; | |
| @@ -1353,6 +1353,14 @@ W: http://wireless.kernel.org/en/users/Drivers/ath9k · 1352 unmodified lines | ||
| 1353 | 1353 | S: Supported |
| 1354 | 1354 | F: drivers/net/wireless/ath/ath9k/ |
| 1355 | 1355 | |
| 1356 | +WILOCITY WIL6210 WIRELESS DRIVER | |
| 1357 | +M: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> | |
| 1358 | +L: linux-wireless@vger.kernel.org | |
| 1359 | +L: wil6210@qca.qualcomm.com | |
| 1360 | +S: Supported | |
| 1361 | +W: http://wireless.kernel.org/en/users/Drivers/wil6210 | |
| 1362 | +F: drivers/net/wireless/ath/wil6210/ | |
| 1363 | + | |
| 1356 | 1364 | CARL9170 LINUX COMMUNITY WIRELESS DRIVER |
| 1357 | 1365 | M: Christian Lamparter <chunkeey@googlemail.com> |
| 1358 | 1366 | L: linux-wireless@vger.kernel.org |
| @@ -62,7 +62,7 @@ static int __init uart8250_init_bcma(void) · 61 unmodified lines | ||
| 62 | 62 | |
| 63 | 63 | p->mapbase = (unsigned int) bcma_port->regs; |
| 64 | 64 | p->membase = (void *) bcma_port->regs; |
| 65 | − p->irq = bcma_port->irq + 2; | |
| 65 | + p->irq = bcma_port->irq; | |
| 66 | 66 | p->uartclk = bcma_port->baud_base; |
| 67 | 67 | p->regshift = bcma_port->reg_shift; |
| 68 | 68 | p->iotype = UPIO_MEM; |
| @@ -67,8 +67,7 @@ config BCMA_DRIVER_GMAC_CMN · 66 unmodified lines | ||
| 67 | 67 | |
| 68 | 68 | config BCMA_DRIVER_GPIO |
| 69 | 69 | bool "BCMA GPIO driver" |
| 70 | − depends on BCMA | |
| 71 | − select GPIOLIB | |
| 70 | + depends on BCMA && GPIOLIB | |
| 72 | 71 | help |
| 73 | 72 | Driver to provide access to the GPIO pins of the bcma bus. |
| 74 | 73 | |
| @@ -31,6 +31,8 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, · 30 unmodified lines | ||
| 31 | 31 | int bcma_bus_suspend(struct bcma_bus *bus); |
| 32 | 32 | int bcma_bus_resume(struct bcma_bus *bus); |
| 33 | 33 | #endif |
| 34 | +struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid, | |
| 35 | + u8 unit); | |
| 34 | 36 | |
| 35 | 37 | /* scan.c */ |
| 36 | 38 | int bcma_bus_scan(struct bcma_bus *bus); |
| @@ -329,7 +329,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc) · 328 unmodified lines | ||
| 329 | 329 | return; |
| 330 | 330 | } |
| 331 | 331 | |
| 332 | − irq = bcma_core_mips_irq(cc->core); | |
| 332 | + irq = bcma_core_irq(cc->core); | |
| 333 | 333 | |
| 334 | 334 | /* Determine the registers of the UARTs */ |
| 335 | 335 | cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART); |
| @@ -35,7 +35,7 @@ static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = { · 34 unmodified lines | ||
| 35 | 35 | { "M25P40", 0x12, 0x10000, 8, }, |
| 36 | 36 | |
| 37 | 37 | { "M25P16", 0x14, 0x10000, 32, }, |
| 38 | − { "M25P32", 0x14, 0x10000, 64, }, | |
| 38 | + { "M25P32", 0x15, 0x10000, 64, }, | |
| 39 | 39 | { "M25P64", 0x16, 0x10000, 128, }, |
| 40 | 40 | { "M25FL128", 0x17, 0x10000, 256, }, |
| 41 | 41 | { 0 }, |
| @@ -74,28 +74,41 @@ static u32 bcma_core_mips_irqflag(struct bcma_device *dev) · 73 unmodified lines | ||
| 74 | 74 | return dev->core_index; |
| 75 | 75 | flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30); |
| 76 | 76 | |
| 77 | − return flag & 0x1F; | |
| 77 | + if (flag) | |
| 78 | + return flag & 0x1F; | |
| 79 | + else | |
| 80 | + return 0x3f; | |
| 78 | 81 | } |
| 79 | 82 | |
| 80 | 83 | /* Get the MIPS IRQ assignment for a specified device. |
| 81 | 84 | * If unassigned, 0 is returned. |
| 85 | + * If disabled, 5 is returned. | |
| 86 | + * If not supported, 6 is returned. | |
| 82 | 87 | */ |
| 83 | −unsigned int bcma_core_mips_irq(struct bcma_device *dev) | |
| 88 | +static unsigned int bcma_core_mips_irq(struct bcma_device *dev) | |
| 84 | 89 | { |
| 85 | 90 | struct bcma_device *mdev = dev->bus->drv_mips.core; |
| 86 | 91 | u32 irqflag; |
| 87 | 92 | unsigned int irq; |
| 88 | 93 | |
| 89 | 94 | irqflag = bcma_core_mips_irqflag(dev); |
| 95 | + if (irqflag == 0x3f) | |
| 96 | + return 6; | |
| 90 | 97 | |
| 91 | − for (irq = 1; irq <= 4; irq++) | |
| 98 | + for (irq = 0; irq <= 4; irq++) | |
| 92 | 99 | if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) & |
| 93 | 100 | (1 << irqflag)) |
| 94 | 101 | return irq; |
| 95 | 102 | |
| 96 | − return 0; | |
| 103 | + return 5; | |
| 104 | +} | |
| 105 | + | |
| 106 | +unsigned int bcma_core_irq(struct bcma_device *dev) | |
| 107 | +{ | |
| 108 | + unsigned int mips_irq = bcma_core_mips_irq(dev); | |
| 109 | + return mips_irq <= 4 ? mips_irq + 2 : 0; | |
| 97 | 110 | } |
| 98 | −EXPORT_SYMBOL(bcma_core_mips_irq); | |
| 111 | +EXPORT_SYMBOL(bcma_core_irq); | |
| 99 | 112 | |
| 100 | 113 | static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) |
| 101 | 114 | { |
| @@ -114,7 +127,7 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) · 12 unmodified lines | ||
| 114 | 127 | bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0), |
| 115 | 128 | bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) & |
| 116 | 129 | ~(1 << irqflag)); |
| 117 | − else | |
| 130 | + else if (oldirq != 5) | |
| 118 | 131 | bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0); |
| 119 | 132 | |
| 120 | 133 | /* assign the new one */ |
| @@ -123,9 +136,9 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) · 2 unmodified lines | ||
| 123 | 136 | bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) | |
| 124 | 137 | (1 << irqflag)); |
| 125 | 138 | } else { |
| 126 | − u32 oldirqflag = bcma_read32(mdev, | |
| 127 | − BCMA_MIPS_MIPS74K_INTMASK(irq)); | |
| 128 | − if (oldirqflag) { | |
| 139 | + u32 irqinitmask = bcma_read32(mdev, | |
| 140 | + BCMA_MIPS_MIPS74K_INTMASK(irq)); | |
| 141 | + if (irqinitmask) { | |
| 129 | 142 | struct bcma_device *core; |
| 130 | 143 | |
| 131 | 144 | /* backplane irq line is in use, find out who uses |
| @@ -133,7 +146,7 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) · 1 unmodified line | ||
| 133 | 146 | */ |
| 134 | 147 | list_for_each_entry(core, &bus->cores, list) { |
| 135 | 148 | if ((1 << bcma_core_mips_irqflag(core)) == |
| 136 | − oldirqflag) { | |
| 149 | + irqinitmask) { | |
| 137 | 150 | bcma_core_mips_set_irq(core, 0); |
| 138 | 151 | break; |
| 139 | 152 | } |
| @@ -143,15 +156,31 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) · 3 unmodified lines | ||
| 143 | 156 | 1 << irqflag); |
| 144 | 157 | } |
| 145 | 158 | |
| 146 | − bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n", | |
| 147 | − dev->id.id, oldirq + 2, irq + 2); | |
| 159 | + bcma_debug(bus, "set_irq: core 0x%04x, irq %d => %d\n", | |
| 160 | + dev->id.id, oldirq <= 4 ? oldirq + 2 : 0, irq + 2); | |
| 161 | +} | |
| 162 | + | |
| 163 | +static void bcma_core_mips_set_irq_name(struct bcma_bus *bus, unsigned int irq, | |
| 164 | + u16 coreid, u8 unit) | |
| 165 | +{ | |
| 166 | + struct bcma_device *core; | |
| 167 | + | |
| 168 | + core = bcma_find_core_unit(bus, coreid, unit); | |
| 169 | + if (!core) { | |
| 170 | + bcma_warn(bus, | |
| 171 | + "Can not find core (id: 0x%x, unit %i) for IRQ configuration.\n", | |
| 172 | + coreid, unit); | |
| 173 | + return; | |
| 174 | + } | |
| 175 | + | |
| 176 | + bcma_core_mips_set_irq(core, irq); | |
| 148 | 177 | } |
| 149 | 178 | |
| 150 | 179 | static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq) |
| 151 | 180 | { |
| 152 | 181 | int i; |
| 153 | 182 | static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"}; |
| 154 | − printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id); | |
| 183 | + printk(KERN_DEBUG KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id); | |
| 155 | 184 | for (i = 0; i <= 6; i++) |
| 156 | 185 | printk(" %s%s", irq_name[i], i == irq ? "*" : " "); |
| 157 | 186 | printk("\n"); |
| @@ -227,6 +256,32 @@ void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) · 69 unmodified lines | ||
| 227 | 256 | mcore->early_setup_done = true; |
| 228 | 257 | } |
| 229 | 258 | |
| 259 | +static void bcma_fix_i2s_irqflag(struct bcma_bus *bus) | |
| 260 | +{ | |
| 261 | + struct bcma_device *cpu, *pcie, *i2s; | |
| 262 | + | |
| 263 | + /* Fixup the interrupts in 4716/4748 for i2s core (2010 Broadcom SDK) | |
| 264 | + * (IRQ flags > 7 are ignored when setting the interrupt masks) | |
| 265 | + */ | |
| 266 | + if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4716 && | |
| 267 | + bus->chipinfo.id != BCMA_CHIP_ID_BCM4748) | |
| 268 | + return; | |
| 269 | + | |
| 270 | + cpu = bcma_find_core(bus, BCMA_CORE_MIPS_74K); | |
| 271 | + pcie = bcma_find_core(bus, BCMA_CORE_PCIE); | |
| 272 | + i2s = bcma_find_core(bus, BCMA_CORE_I2S); | |
| 273 | + if (cpu && pcie && i2s && | |
| 274 | + bcma_aread32(cpu, BCMA_MIPS_OOBSELINA74) == 0x08060504 && | |
| 275 | + bcma_aread32(pcie, BCMA_MIPS_OOBSELINA74) == 0x08060504 && | |
| 276 | + bcma_aread32(i2s, BCMA_MIPS_OOBSELOUTA30) == 0x88) { | |
| 277 | + bcma_awrite32(cpu, BCMA_MIPS_OOBSELINA74, 0x07060504); | |
| 278 | + bcma_awrite32(pcie, BCMA_MIPS_OOBSELINA74, 0x07060504); | |
| 279 | + bcma_awrite32(i2s, BCMA_MIPS_OOBSELOUTA30, 0x87); | |
| 280 | + bcma_debug(bus, | |
| 281 | + "Moved i2s interrupt to oob line 7 instead of 8\n"); | |
| 282 | + } | |
| 283 | +} | |
| 284 | + | |
| 230 | 285 | void bcma_core_mips_init(struct bcma_drv_mips *mcore) |
| 231 | 286 | { |
| 232 | 287 | struct bcma_bus *bus; |
| @@ -236,43 +291,55 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore) · 3 unmodified lines | ||
| 236 | 291 | if (mcore->setup_done) |
| 237 | 292 | return; |
| 238 | 293 | |
| 239 | − bcma_info(bus, "Initializing MIPS core...\n"); | |
| 294 | + bcma_debug(bus, "Initializing MIPS core...\n"); | |
| 240 | 295 | |
| 241 | 296 | bcma_core_mips_early_init(mcore); |
| 242 | 297 | |
| 243 | − mcore->assigned_irqs = 1; | |
| 244 | − | |
| 245 | − /* Assign IRQs to all cores on the bus */ | |
| 246 | − list_for_each_entry(core, &bus->cores, list) { | |
| 247 | − int mips_irq; | |
| 248 | − if (core->irq) | |
| 249 | − continue; | |
| 250 | − | |
| 251 | − mips_irq = bcma_core_mips_irq(core); | |
| 252 | − if (mips_irq > 4) | |
| 253 | − core->irq = 0; | |
| 254 | − else | |
| 255 | − core->irq = mips_irq + 2; | |
| 256 | − if (core->irq > 5) | |
| 257 | − continue; | |
| 258 | − switch (core->id.id) { | |
| 259 | − case BCMA_CORE_PCI: | |
| 260 | − case BCMA_CORE_PCIE: | |
| 261 | − case BCMA_CORE_ETHERNET: | |
| 262 | − case BCMA_CORE_ETHERNET_GBIT: | |
| 263 | − case BCMA_CORE_MAC_GBIT: | |
| 264 | − case BCMA_CORE_80211: | |
| 265 | − case BCMA_CORE_USB20_HOST: | |
| 266 | − /* These devices get their own IRQ line if available, | |
| 267 | − * the rest goes on IRQ0 | |
| 268 | − */ | |
| 269 | − if (mcore->assigned_irqs <= 4) | |
| 270 | − bcma_core_mips_set_irq(core, | |
| 271 | − mcore->assigned_irqs++); | |
| 272 | − break; | |
| 298 | + bcma_fix_i2s_irqflag(bus); | |
| 299 | + | |
| 300 | + switch (bus->chipinfo.id) { | |
| 301 | + case BCMA_CHIP_ID_BCM4716: | |
| 302 | + case BCMA_CHIP_ID_BCM4748: | |
| 303 | + bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0); | |
| 304 | + bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0); | |
| 305 | + bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0); | |
| 306 | + bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_PCIE, 0); | |
| 307 | + bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0); | |
| 308 | + bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0); | |
| 309 | + break; | |
| 310 | + case BCMA_CHIP_ID_BCM5356: | |
| 311 | + case BCMA_CHIP_ID_BCM47162: | |
| 312 | + case BCMA_CHIP_ID_BCM53572: | |
| 313 | + bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0); | |
| 314 | + bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0); | |
| 315 | + bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0); | |
| 316 | + break; | |
| 317 | + case BCMA_CHIP_ID_BCM5357: | |
| 318 | + case BCMA_CHIP_ID_BCM4749: | |
| 319 | + bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0); | |
| 320 | + bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0); | |
| 321 | + bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0); | |
| 322 | + bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0); | |
| 323 | + bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0); | |
| 324 | + break; | |
| 325 | + case BCMA_CHIP_ID_BCM4706: | |
| 326 | + bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_PCIE, 0); | |
| 327 | + bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_4706_MAC_GBIT, | |
| 328 | + 0); | |
| 329 | + bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_PCIE, 1); | |
| 330 | + bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_USB20_HOST, 0); | |
| 331 | + bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_4706_CHIPCOMMON, | |
| 332 | + 0); | |
| 333 | + break; | |
| 334 | + default: | |
| 335 | + list_for_each_entry(core, &bus->cores, list) { | |
| 336 | + core->irq = bcma_core_irq(core); | |
| 273 | 337 | } |
| 338 | + bcma_err(bus, | |
| 339 | + "Unknown device (0x%x) found, can not configure IRQs\n", | |
| 340 | + bus->chipinfo.id); | |
| 274 | 341 | } |
| 275 | − bcma_info(bus, "IRQ reconfiguration done\n"); | |
| 342 | + bcma_debug(bus, "IRQ reconfiguration done\n"); | |
| 276 | 343 | bcma_core_mips_dump_irq(bus); |
| 277 | 344 | |
| 278 | 345 | mcore->setup_done = true; |
| @@ -94,19 +94,19 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev, · 93 unmodified lines | ||
| 94 | 94 | if (dev == 0) { |
| 95 | 95 | /* we support only two functions on device 0 */ |
| 96 | 96 | if (func > 1) |
| 97 | − return -EINVAL; | |
| 97 | + goto out; | |
| 98 | 98 | |
| 99 | 99 | /* accesses to config registers with offsets >= 256 |
| 100 | 100 | * requires indirect access. |
| 101 | 101 | */ |
| 102 | 102 | if (off >= PCI_CONFIG_SPACE_SIZE) { |
| 103 | 103 | addr = (func << 12); |
| 104 | − addr |= (off & 0x0FFF); | |
| 104 | + addr |= (off & 0x0FFC); | |
| 105 | 105 | val = bcma_pcie_read_config(pc, addr); |
| 106 | 106 | } else { |
| 107 | 107 | addr = BCMA_CORE_PCI_PCICFG0; |
| 108 | 108 | addr |= (func << 8); |
| 109 | − addr |= (off & 0xfc); | |
| 109 | + addr |= (off & 0xFC); | |
| 110 | 110 | val = pcicore_read32(pc, addr); |
| 111 | 111 | } |
| 112 | 112 | } else { |
| @@ -119,11 +119,9 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev, · 6 unmodified lines | ||
| 119 | 119 | goto out; |
| 120 | 120 | |
| 121 | 121 | if (mips_busprobe32(val, mmio)) { |
| 122 | − val = 0xffffffff; | |
| 122 | + val = 0xFFFFFFFF; | |
| 123 | 123 | goto unmap; |
| 124 | 124 | } |
| 125 | − | |
| 126 | − val = readl(mmio); | |
| 127 | 125 | } |
| 128 | 126 | val >>= (8 * (off & 3)); |
| 129 | 127 | |
| @@ -151,7 +149,7 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev, · 21 unmodified lines | ||
| 151 | 149 | const void *buf, int len) |
| 152 | 150 | { |
| 153 | 151 | int err = -EINVAL; |
| 154 | − u32 addr = 0, val = 0; | |
| 152 | + u32 addr, val; | |
| 155 | 153 | void __iomem *mmio = 0; |
| 156 | 154 | u16 chipid = pc->core->bus->chipinfo.id; |
| 157 | 155 | |
| @@ -159,16 +157,22 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev, · 1 unmodified line | ||
| 159 | 157 | if (unlikely(len != 1 && len != 2 && len != 4)) |
| 160 | 158 | goto out; |
| 161 | 159 | if (dev == 0) { |
| 160 | + /* we support only two functions on device 0 */ | |
| 161 | + if (func > 1) | |
| 162 | + goto out; | |
| 163 | + | |
| 162 | 164 | /* accesses to config registers with offsets >= 256 |
| 163 | 165 | * requires indirect access. |
| 164 | 166 | */ |
| 165 | − if (off < PCI_CONFIG_SPACE_SIZE) { | |
| 166 | − addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0; | |
| 167 | + if (off >= PCI_CONFIG_SPACE_SIZE) { | |
| 168 | + addr = (func << 12); | |
| 169 | + addr |= (off & 0x0FFC); | |
| 170 | + val = bcma_pcie_read_config(pc, addr); | |
| 171 | + } else { | |
| 172 | + addr = BCMA_CORE_PCI_PCICFG0; | |
| 167 | 173 | addr |= (func << 8); |
| 168 | − addr |= (off & 0xfc); | |
| 169 | − mmio = ioremap_nocache(addr, sizeof(val)); | |
| 170 | − if (!mmio) | |
| 171 | − goto out; | |
| 174 | + addr |= (off & 0xFC); | |
| 175 | + val = pcicore_read32(pc, addr); | |
| 172 | 176 | } |
| 173 | 177 | } else { |
| 174 | 178 | addr = bcma_get_cfgspace_addr(pc, dev, func, off); |
| @@ -180,19 +184,17 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev, · 5 unmodified lines | ||
| 180 | 184 | goto out; |
| 181 | 185 | |
| 182 | 186 | if (mips_busprobe32(val, mmio)) { |
| 183 | − val = 0xffffffff; | |
| 187 | + val = 0xFFFFFFFF; | |
| 184 | 188 | goto unmap; |
| 185 | 189 | } |
| 186 | 190 | } |
| 187 | 191 | |
| 188 | 192 | switch (len) { |
| 189 | 193 | case 1: |
| 190 | − val = readl(mmio); | |
| 191 | 194 | val &= ~(0xFF << (8 * (off & 3))); |
| 192 | 195 | val |= *((const u8 *)buf) << (8 * (off & 3)); |
| 193 | 196 | break; |
| 194 | 197 | case 2: |
| 195 | − val = readl(mmio); | |
| 196 | 198 | val &= ~(0xFFFF << (8 * (off & 3))); |
| 197 | 199 | val |= *((const u16 *)buf) << (8 * (off & 3)); |
| 198 | 200 | break; |
| @@ -200,13 +202,14 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev, · 1 unmodified line | ||
| 200 | 202 | val = *((const u32 *)buf); |
| 201 | 203 | break; |
| 202 | 204 | } |
| 203 | − if (dev == 0 && !addr) { | |
| 205 | + if (dev == 0) { | |
| 204 | 206 | /* accesses to config registers with offsets >= 256 |
| 205 | 207 | * requires indirect access. |
| 206 | 208 | */ |
| 207 | − addr = (func << 12); | |
| 208 | − addr |= (off & 0x0FFF); | |
| 209 | − bcma_pcie_write_config(pc, addr, val); | |
| 209 | + if (off >= PCI_CONFIG_SPACE_SIZE) | |
| 210 | + bcma_pcie_write_config(pc, addr, val); | |
| 211 | + else | |
| 212 | + pcicore_write32(pc, addr, val); | |
| 210 | 213 | } else { |
| 211 | 214 | writel(val, mmio); |
| 212 | 215 | |
| @@ -277,7 +280,7 @@ static u8 __devinit bcma_find_pci_capability(struct bcma_drv_pci *pc, · 64 unmodified lines | ||
| 277 | 280 | /* check for Header type 0 */ |
| 278 | 281 | bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val, |
| 279 | 282 | sizeof(u8)); |
| 280 | − if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL) | |
| 283 | + if ((byte_val & 0x7F) != PCI_HEADER_TYPE_NORMAL) | |
| 281 | 284 | return cap_ptr; |
| 282 | 285 | |
| 283 | 286 | /* check if the capability pointer field exists */ |
| @@ -427,7 +430,7 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) · 143 unmodified lines | ||
| 427 | 430 | /* Reset RC */ |
| 428 | 431 | usleep_range(3000, 5000); |
| 429 | 432 | pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE); |
| 430 | − usleep_range(1000, 2000); | |
| 433 | + msleep(50); | |
| 431 | 434 | pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST | |
| 432 | 435 | BCMA_CORE_PCI_CTL_RST_OE); |
| 433 | 436 | |
| @@ -489,6 +492,17 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) · 55 unmodified lines | ||
| 489 | 492 | |
| 490 | 493 | bcma_core_pci_enable_crs(pc); |
| 491 | 494 | |
| 495 | + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706 || | |
| 496 | + bus->chipinfo.id == BCMA_CHIP_ID_BCM4716) { | |
| 497 | + u16 val16; | |
| 498 | + bcma_extpci_read_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL, | |
| 499 | + &val16, sizeof(val16)); | |
| 500 | + val16 |= (2 << 5); /* Max payload size of 512 */ | |
| 501 | + val16 |= (2 << 12); /* MRRS 512 */ | |
| 502 | + bcma_extpci_write_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL, | |
| 503 | + &val16, sizeof(val16)); | |
| 504 | + } | |
| 505 | + | |
| 492 | 506 | /* Enable PCI bridge BAR0 memory & master access */ |
| 493 | 507 | tmp = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; |
| 494 | 508 | bcma_extpci_write_config(pc, 0, 0, PCI_COMMAND, &tmp, sizeof(tmp)); |
| @@ -577,7 +591,7 @@ int bcma_core_pci_plat_dev_init(struct pci_dev *dev) · 82 unmodified lines | ||
| 577 | 591 | pr_info("PCI: Fixing up device %s\n", pci_name(dev)); |
| 578 | 592 | |
| 579 | 593 | /* Fix up interrupt lines */ |
| 580 | − dev->irq = bcma_core_mips_irq(pc_host->pdev->core) + 2; | |
| 594 | + dev->irq = bcma_core_irq(pc_host->pdev->core); | |
| 581 | 595 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); |
| 582 | 596 | |
| 583 | 597 | return 0; |
| @@ -596,6 +610,6 @@ int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev) · 12 unmodified lines | ||
| 596 | 610 | |
| 597 | 611 | pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host, |
| 598 | 612 | pci_ops); |
| 599 | − return bcma_core_mips_irq(pc_host->pdev->core) + 2; | |
| 613 | + return bcma_core_irq(pc_host->pdev->core); | |
| 600 | 614 | } |
| 601 | 615 | EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq); |
| @@ -81,8 +81,8 @@ struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid) · 80 unmodified lines | ||
| 81 | 81 | } |
| 82 | 82 | EXPORT_SYMBOL_GPL(bcma_find_core); |
| 83 | 83 | |
| 84 | −static struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid, | |
| 85 | − u8 unit) | |
| 84 | +struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid, | |
| 85 | + u8 unit) | |
| 86 | 86 | { |
| 87 | 87 | struct bcma_device *core; |
| 88 | 88 | |
| @@ -77,10 +77,15 @@ static struct usb_device_id ath3k_table[] = { · 76 unmodified lines | ||
| 77 | 77 | { USB_DEVICE(0x0CF3, 0x311D) }, |
| 78 | 78 | { USB_DEVICE(0x13d3, 0x3375) }, |
| 79 | 79 | { USB_DEVICE(0x04CA, 0x3005) }, |
| 80 | + { USB_DEVICE(0x04CA, 0x3006) }, | |
| 81 | + { USB_DEVICE(0x04CA, 0x3008) }, | |
| 80 | 82 | { USB_DEVICE(0x13d3, 0x3362) }, |
| 81 | 83 | { USB_DEVICE(0x0CF3, 0xE004) }, |
| 82 | 84 | { USB_DEVICE(0x0930, 0x0219) }, |
| 83 | 85 | { USB_DEVICE(0x0489, 0xe057) }, |
| 86 | + { USB_DEVICE(0x13d3, 0x3393) }, | |
| 87 | + { USB_DEVICE(0x0489, 0xe04e) }, | |
| 88 | + { USB_DEVICE(0x0489, 0xe056) }, | |
| 84 | 89 | |
| 85 | 90 | /* Atheros AR5BBU12 with sflash firmware */ |
| 86 | 91 | { USB_DEVICE(0x0489, 0xE02C) }, |
| @@ -104,10 +109,15 @@ static struct usb_device_id ath3k_blist_tbl[] = { · 17 unmodified lines | ||
| 104 | 109 | { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, |
| 105 | 110 | { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, |
| 106 | 111 | { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, |
| 112 | + { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, | |
| 113 | + { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, | |
| 107 | 114 | { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, |
| 108 | 115 | { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, |
| 109 | 116 | { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, |
| 110 | 117 | { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, |
| 118 | + { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, | |
| 119 | + { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, | |
| 120 | + { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, | |
| 111 | 121 | |
| 112 | 122 | /* Atheros AR5BBU22 with sflash firmware */ |
| 113 | 123 | { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, |
| @@ -135,10 +135,15 @@ static struct usb_device_id blacklist_table[] = { · 134 unmodified lines | ||
| 135 | 135 | { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, |
| 136 | 136 | { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, |
| 137 | 137 | { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, |
| 138 | + { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, | |
| 139 | + { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, | |
| 138 | 140 | { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, |
| 139 | 141 | { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, |
| 140 | 142 | { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, |
| 141 | 143 | { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, |
| 144 | + { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, | |
| 145 | + { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, | |
| 146 | + { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, | |
| 142 | 147 | |
| 143 | 148 | /* Atheros AR5BBU12 with sflash firmware */ |
| 144 | 149 | { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, |
| @@ -30,5 +30,6 @@ source "drivers/net/wireless/ath/ath9k/Kconfig" · 29 unmodified lines | ||
| 30 | 30 | source "drivers/net/wireless/ath/carl9170/Kconfig" |
| 31 | 31 | source "drivers/net/wireless/ath/ath6kl/Kconfig" |
| 32 | 32 | source "drivers/net/wireless/ath/ar5523/Kconfig" |
| 33 | +source "drivers/net/wireless/ath/wil6210/Kconfig" | |
| 33 | 34 | |
| 34 | 35 | endif |
| @@ -3,6 +3,7 @@ obj-$(CONFIG_ATH9K_HW) += ath9k/ · 2 unmodified lines | ||
| 3 | 3 | obj-$(CONFIG_CARL9170) += carl9170/ |
| 4 | 4 | obj-$(CONFIG_ATH6KL) += ath6kl/ |
| 5 | 5 | obj-$(CONFIG_AR5523) += ar5523/ |
| 6 | +obj-$(CONFIG_WIL6210) += wil6210/ | |
| 6 | 7 | |
| 7 | 8 | obj-$(CONFIG_ATH_COMMON) += ath.o |
| 8 | 9 | |
| @@ -2,6 +2,7 @@ config ATH9K_HW · 1 unmodified line | ||
| 2 | 2 | tristate |
| 3 | 3 | config ATH9K_COMMON |
| 4 | 4 | tristate |
| 5 | + select ATH_COMMON | |
| 5 | 6 | config ATH9K_DFS_DEBUGFS |
| 6 | 7 | def_bool y |
| 7 | 8 | depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED |
| @@ -17,7 +18,6 @@ config ATH9K_BTCOEX_SUPPORT · 9 unmodified lines | ||
| 17 | 18 | config ATH9K |
| 18 | 19 | tristate "Atheros 802.11n wireless cards support" |
| 19 | 20 | depends on MAC80211 |
| 20 | − select ATH_COMMON | |
| 21 | 21 | select ATH9K_HW |
| 22 | 22 | select MAC80211_LEDS |
| 23 | 23 | select LEDS_CLASS |
| @@ -56,7 +56,8 @@ config ATH9K_AHB · 32 unmodified lines | ||
| 56 | 56 | |
| 57 | 57 | config ATH9K_DEBUGFS |
| 58 | 58 | bool "Atheros ath9k debugging" |
| 59 | − depends on ATH9K && DEBUG_FS | |
| 59 | + depends on ATH9K | |
| 60 | + select MAC80211_DEBUGFS | |
| 60 | 61 | ---help--- |
| 61 | 62 | Say Y, if you need access to ath9k's statistics for |
| 62 | 63 | interrupts, rate control, etc. |
| @@ -86,29 +86,25 @@ static int ath_ahb_probe(struct platform_device *pdev) · 85 unmodified lines | ||
| 86 | 86 | |
| 87 | 87 | if (!pdev->dev.platform_data) { |
| 88 | 88 | dev_err(&pdev->dev, "no platform data specified\n"); |
| 89 | − ret = -EINVAL; | |
| 90 | − goto err_out; | |
| 89 | + return -EINVAL; | |
| 91 | 90 | } |
| 92 | 91 | |
| 93 | 92 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 94 | 93 | if (res == NULL) { |
| 95 | 94 | dev_err(&pdev->dev, "no memory resource found\n"); |
| 96 | − ret = -ENXIO; | |
| 97 | − goto err_out; | |
| 95 | + return -ENXIO; | |
| 98 | 96 | } |
| 99 | 97 | |
| 100 | − mem = ioremap_nocache(res->start, resource_size(res)); | |
| 98 | + mem = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); | |
| 101 | 99 | if (mem == NULL) { |
| 102 | 100 | dev_err(&pdev->dev, "ioremap failed\n"); |
| 103 | − ret = -ENOMEM; | |
| 104 | − goto err_out; | |
| 101 | + return -ENOMEM; | |
| 105 | 102 | } |
| 106 | 103 | |
| 107 | 104 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| 108 | 105 | if (res == NULL) { |
| 109 | 106 | dev_err(&pdev->dev, "no IRQ resource found\n"); |
| 110 | − ret = -ENXIO; | |
| 111 | − goto err_iounmap; | |
| 107 | + return -ENXIO; | |
| 112 | 108 | } |
| 113 | 109 | |
| 114 | 110 | irq = res->start; |
| @@ -116,8 +112,7 @@ static int ath_ahb_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 116 | 112 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); |
| 117 | 113 | if (hw == NULL) { |
| 118 | 114 | dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); |
| 119 | − ret = -ENOMEM; | |
| 120 | − goto err_iounmap; | |
| 115 | + return -ENOMEM; | |
| 121 | 116 | } |
| 122 | 117 | |
| 123 | 118 | SET_IEEE80211_DEV(hw, &pdev->dev); |
| @@ -156,9 +151,6 @@ static int ath_ahb_probe(struct platform_device *pdev) · 32 unmodified lines | ||
| 156 | 151 | err_free_hw: |
| 157 | 152 | ieee80211_free_hw(hw); |
| 158 | 153 | platform_set_drvdata(pdev, NULL); |
| 159 | − err_iounmap: | |
| 160 | − iounmap(mem); | |
| 161 | − err_out: | |
| 162 | 154 | return ret; |
| 163 | 155 | } |
| 164 | 156 | |
| @@ -168,12 +160,10 @@ static int ath_ahb_remove(struct platform_device *pdev) · 3 unmodified lines | ||
| 168 | 160 | |
| 169 | 161 | if (hw) { |
| 170 | 162 | struct ath_softc *sc = hw->priv; |
| 171 | − void __iomem *mem = sc->mem; | |
| 172 | 163 | |
| 173 | 164 | ath9k_deinit_device(sc); |
| 174 | 165 | free_irq(sc->irq, sc); |
| 175 | 166 | ieee80211_free_hw(sc->hw); |
| 176 | − iounmap(mem); | |
| 177 | 167 | platform_set_drvdata(pdev, NULL); |
| 178 | 168 | } |
| 179 | 169 | |
| @@ -152,7 +152,8 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, · 151 unmodified lines | ||
| 152 | 152 | ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", |
| 153 | 153 | aniState->ofdmNoiseImmunityLevel, |
| 154 | 154 | immunityLevel, BEACON_RSSI(ah), |
| 155 | − aniState->rssiThrLow, aniState->rssiThrHigh); | |
| 155 | + ATH9K_ANI_RSSI_THR_LOW, | |
| 156 | + ATH9K_ANI_RSSI_THR_HIGH); | |
| 156 | 157 | |
| 157 | 158 | if (!scan) |
| 158 | 159 | aniState->ofdmNoiseImmunityLevel = immunityLevel; |
| @@ -173,7 +174,7 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, · 14 unmodified lines | ||
| 173 | 174 | |
| 174 | 175 | weak_sig = entry_ofdm->ofdm_weak_signal_on; |
| 175 | 176 | if (ah->opmode == NL80211_IFTYPE_STATION && |
| 176 | − BEACON_RSSI(ah) <= aniState->rssiThrHigh) | |
| 177 | + BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH) | |
| 177 | 178 | weak_sig = true; |
| 178 | 179 | |
| 179 | 180 | if (aniState->ofdmWeakSigDetect != weak_sig) |
| @@ -216,11 +217,11 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, · 36 unmodified lines | ||
| 216 | 217 | |
| 217 | 218 | ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", |
| 218 | 219 | aniState->cckNoiseImmunityLevel, immunityLevel, |
| 219 | − BEACON_RSSI(ah), aniState->rssiThrLow, | |
| 220 | − aniState->rssiThrHigh); | |
| 220 | + BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW, | |
| 221 | + ATH9K_ANI_RSSI_THR_HIGH); | |
| 221 | 222 | |
| 222 | 223 | if (ah->opmode == NL80211_IFTYPE_STATION && |
| 223 | − BEACON_RSSI(ah) <= aniState->rssiThrLow && | |
| 224 | + BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW && | |
| 224 | 225 | immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI) |
| 225 | 226 | immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI; |
| 226 | 227 | |
| @@ -418,9 +419,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) · 191 unmodified lines | ||
| 418 | 419 | return; |
| 419 | 420 | |
| 420 | 421 | aniState = &ah->curchan->ani; |
| 421 | − if (WARN_ON(!aniState)) | |
| 422 | − return; | |
| 423 | − | |
| 424 | 422 | if (!ath9k_hw_ani_read_counters(ah)) |
| 425 | 423 | return; |
| 426 | 424 | |
| @@ -489,23 +487,6 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah) · 62 unmodified lines | ||
| 489 | 487 | } |
| 490 | 488 | EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); |
| 491 | 489 | |
| 492 | −void ath9k_hw_ani_setup(struct ath_hw *ah) | |
| 493 | −{ | |
| 494 | − int i; | |
| 495 | − | |
| 496 | − static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; | |
| 497 | − static const int coarseHigh[] = { -14, -14, -14, -14, -12 }; | |
| 498 | − static const int coarseLow[] = { -64, -64, -64, -64, -70 }; | |
| 499 | − static const int firpwr[] = { -78, -78, -78, -78, -80 }; | |
| 500 | − | |
| 501 | − for (i = 0; i < 5; i++) { | |
| 502 | − ah->totalSizeDesired[i] = totalSizeDesired[i]; | |
| 503 | − ah->coarse_high[i] = coarseHigh[i]; | |
| 504 | − ah->coarse_low[i] = coarseLow[i]; | |
| 505 | − ah->firpwr[i] = firpwr[i]; | |
| 506 | − } | |
| 507 | −} | |
| 508 | − | |
| 509 | 490 | void ath9k_hw_ani_init(struct ath_hw *ah) |
| 510 | 491 | { |
| 511 | 492 | struct ath_common *common = ath9k_hw_common(ah); |
| @@ -531,8 +512,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah) · 19 unmodified lines | ||
| 531 | 512 | |
| 532 | 513 | ani->ofdmsTurn = true; |
| 533 | 514 | |
| 534 | − ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; | |
| 535 | − ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; | |
| 536 | 515 | ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; |
| 537 | 516 | ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; |
| 538 | 517 | ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; |
| @@ -104,7 +104,6 @@ struct ath9k_ani_default { · 103 unmodified lines | ||
| 104 | 104 | }; |
| 105 | 105 | |
| 106 | 106 | struct ar5416AniState { |
| 107 | − struct ath9k_channel *c; | |
| 108 | 107 | u8 noiseImmunityLevel; |
| 109 | 108 | u8 ofdmNoiseImmunityLevel; |
| 110 | 109 | u8 cckNoiseImmunityLevel; |
| @@ -113,15 +112,9 @@ struct ar5416AniState { · 2 unmodified lines | ||
| 113 | 112 | u8 spurImmunityLevel; |
| 114 | 113 | u8 firstepLevel; |
| 115 | 114 | u8 ofdmWeakSigDetect; |
| 116 | − u8 cckWeakSigThreshold; | |
| 117 | 115 | u32 listenTime; |
| 118 | − int32_t rssiThrLow; | |
| 119 | − int32_t rssiThrHigh; | |
| 120 | 116 | u32 ofdmPhyErrCount; |
| 121 | 117 | u32 cckPhyErrCount; |
| 122 | − int16_t pktRssi[2]; | |
| 123 | − int16_t ofdmErrRssi[2]; | |
| 124 | − int16_t cckErrRssi[2]; | |
| 125 | 118 | struct ath9k_ani_default iniDef; |
| 126 | 119 | }; |
| 127 | 120 | |
| @@ -147,7 +140,6 @@ struct ar5416Stats { · 19 unmodified lines | ||
| 147 | 140 | |
| 148 | 141 | void ath9k_enable_mib_counters(struct ath_hw *ah); |
| 149 | 142 | void ath9k_hw_disable_mib_counters(struct ath_hw *ah); |
| 150 | −void ath9k_hw_ani_setup(struct ath_hw *ah); | |
| 151 | 143 | void ath9k_hw_ani_init(struct ath_hw *ah); |
| 152 | 144 | |
| 153 | 145 | #endif /* ANI_H */ |
| @@ -466,7 +466,7 @@ static const u32 ar5416Bank0[][2] = { · 465 unmodified lines | ||
| 466 | 466 | }; |
| 467 | 467 | |
| 468 | 468 | static const u32 ar5416BB_RfGain[][3] = { |
| 469 | − /* Addr 5G_HT20 5G_HT40 */ | |
| 469 | + /* Addr 5G 2G */ | |
| 470 | 470 | {0x00009a00, 0x00000000, 0x00000000}, |
| 471 | 471 | {0x00009a04, 0x00000040, 0x00000040}, |
| 472 | 472 | {0x00009a08, 0x00000080, 0x00000080}, |
| @@ -546,12 +546,12 @@ static const u32 ar5416Bank2[][2] = { · 73 unmodified lines | ||
| 546 | 546 | }; |
| 547 | 547 | |
| 548 | 548 | static const u32 ar5416Bank3[][3] = { |
| 549 | − /* Addr 5G_HT20 5G_HT40 */ | |
| 549 | + /* Addr 5G 2G */ | |
| 550 | 550 | {0x000098f0, 0x01400018, 0x01c00018}, |
| 551 | 551 | }; |
| 552 | 552 | |
| 553 | 553 | static const u32 ar5416Bank6[][3] = { |
| 554 | − /* Addr 5G_HT20 5G_HT40 */ | |
| 554 | + /* Addr 5G 2G */ | |
| 555 | 555 | {0x0000989c, 0x00000000, 0x00000000}, |
| 556 | 556 | {0x0000989c, 0x00000000, 0x00000000}, |
| 557 | 557 | {0x0000989c, 0x00000000, 0x00000000}, |
| @@ -588,7 +588,7 @@ static const u32 ar5416Bank6[][3] = { · 30 unmodified lines | ||
| 588 | 588 | }; |
| 589 | 589 | |
| 590 | 590 | static const u32 ar5416Bank6TPC[][3] = { |
| 591 | − /* Addr 5G_HT20 5G_HT40 */ | |
| 591 | + /* Addr 5G 2G */ | |
| 592 | 592 | {0x0000989c, 0x00000000, 0x00000000}, |
| 593 | 593 | {0x0000989c, 0x00000000, 0x00000000}, |
| 594 | 594 | {0x0000989c, 0x00000000, 0x00000000}, |
| @@ -470,16 +470,15 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah, · 469 unmodified lines | ||
| 470 | 470 | static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah) |
| 471 | 471 | { |
| 472 | 472 | #define ATH_ALLOC_BANK(bank, size) do { \ |
| 473 | − bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \ | |
| 474 | − if (!bank) { \ | |
| 475 | − ath_err(common, "Cannot allocate RF banks\n"); \ | |
| 476 | − return -ENOMEM; \ | |
| 477 | − } \ | |
| 473 | + bank = devm_kzalloc(ah->dev, sizeof(u32) * size, GFP_KERNEL); \ | |
| 474 | + if (!bank) \ | |
| 475 | + goto error; \ | |
| 478 | 476 | } while (0); |
| 479 | 477 | |
| 480 | 478 | struct ath_common *common = ath9k_hw_common(ah); |
| 481 | 479 | |
| 482 | − BUG_ON(AR_SREV_9280_20_OR_LATER(ah)); | |
| 480 | + if (AR_SREV_9280_20_OR_LATER(ah)) | |
| 481 | + return 0; | |
| 483 | 482 | |
| 484 | 483 | ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows); |
| 485 | 484 | ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows); |
| @@ -492,35 +491,12 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah) · 6 unmodified lines | ||
| 492 | 491 | |
| 493 | 492 | return 0; |
| 494 | 493 | #undef ATH_ALLOC_BANK |
| 494 | +error: | |
| 495 | + ath_err(common, "Cannot allocate RF banks\n"); | |
| 496 | + return -ENOMEM; | |
| 495 | 497 | } |
| 496 | 498 | |
| 497 | 499 | |
| 498 | −/** | |
| 499 | − * ar5008_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers | |
| 500 | − * @ah: atheros hardware struture | |
| 501 | − * For the external AR2133/AR5133 radios banks. | |
| 502 | − */ | |
| 503 | −static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah) | |
| 504 | −{ | |
| 505 | −#define ATH_FREE_BANK(bank) do { \ | |
| 506 | − kfree(bank); \ | |
| 507 | − bank = NULL; \ | |
| 508 | − } while (0); | |
| 509 | − | |
| 510 | − BUG_ON(AR_SREV_9280_20_OR_LATER(ah)); | |
| 511 | − | |
| 512 | − ATH_FREE_BANK(ah->analogBank0Data); | |
| 513 | − ATH_FREE_BANK(ah->analogBank1Data); | |
| 514 | − ATH_FREE_BANK(ah->analogBank2Data); | |
| 515 | − ATH_FREE_BANK(ah->analogBank3Data); | |
| 516 | − ATH_FREE_BANK(ah->analogBank6Data); | |
| 517 | − ATH_FREE_BANK(ah->analogBank6TPCData); | |
| 518 | − ATH_FREE_BANK(ah->analogBank7Data); | |
| 519 | − ATH_FREE_BANK(ah->bank6Temp); | |
| 520 | − | |
| 521 | −#undef ATH_FREE_BANK | |
| 522 | −} | |
| 523 | − | |
| 524 | 500 | /* * |
| 525 | 501 | * ar5008_hw_set_rf_regs - programs rf registers based on EEPROM |
| 526 | 502 | * @ah: atheros hardware structure |
| @@ -1380,7 +1356,7 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah) · 853 unmodified lines | ||
| 1380 | 1356 | conf->radar_inband = 8; |
| 1381 | 1357 | } |
| 1382 | 1358 | |
| 1383 | −void ar5008_hw_attach_phy_ops(struct ath_hw *ah) | |
| 1359 | +int ar5008_hw_attach_phy_ops(struct ath_hw *ah) | |
| 1384 | 1360 | { |
| 1385 | 1361 | struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); |
| 1386 | 1362 | static const u32 ar5416_cca_regs[6] = { |
| @@ -1391,12 +1367,15 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah) · 4 unmodified lines | ||
| 1391 | 1367 | AR_PHY_CH1_EXT_CCA, |
| 1392 | 1368 | AR_PHY_CH2_EXT_CCA |
| 1393 | 1369 | }; |
| 1370 | + int ret; | |
| 1371 | + | |
| 1372 | + ret = ar5008_hw_rf_alloc_ext_banks(ah); | |
| 1373 | + if (ret) | |
| 1374 | + return ret; | |
| 1394 | 1375 | |
| 1395 | 1376 | priv_ops->rf_set_freq = ar5008_hw_set_channel; |
| 1396 | 1377 | priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate; |
| 1397 | 1378 | |
| 1398 | − priv_ops->rf_alloc_ext_banks = ar5008_hw_rf_alloc_ext_banks; | |
| 1399 | − priv_ops->rf_free_ext_banks = ar5008_hw_rf_free_ext_banks; | |
| 1400 | 1379 | priv_ops->set_rf_regs = ar5008_hw_set_rf_regs; |
| 1401 | 1380 | priv_ops->set_channel_regs = ar5008_hw_set_channel_regs; |
| 1402 | 1381 | priv_ops->init_bb = ar5008_hw_init_bb; |
| @@ -1421,4 +1400,5 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah) · 18 unmodified lines | ||
| 1421 | 1400 | ar5008_hw_set_nf_limits(ah); |
| 1422 | 1401 | ar5008_hw_set_radar_conf(ah); |
| 1423 | 1402 | memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs)); |
| 1403 | + return 0; | |
| 1424 | 1404 | } |
| @@ -460,7 +460,7 @@ static const u32 ar5416Common_9100[][2] = { · 459 unmodified lines | ||
| 460 | 460 | }; |
| 461 | 461 | |
| 462 | 462 | static const u32 ar5416Bank6_9100[][3] = { |
| 463 | − /* Addr 5G_HT20 5G_HT40 */ | |
| 463 | + /* Addr 5G 2G */ | |
| 464 | 464 | {0x0000989c, 0x00000000, 0x00000000}, |
| 465 | 465 | {0x0000989c, 0x00000000, 0x00000000}, |
| 466 | 466 | {0x0000989c, 0x00000000, 0x00000000}, |
| @@ -497,7 +497,7 @@ static const u32 ar5416Bank6_9100[][3] = { · 30 unmodified lines | ||
| 497 | 497 | }; |
| 498 | 498 | |
| 499 | 499 | static const u32 ar5416Bank6TPC_9100[][3] = { |
| 500 | − /* Addr 5G_HT20 5G_HT40 */ | |
| 500 | + /* Addr 5G 2G */ | |
| 501 | 501 | {0x0000989c, 0x00000000, 0x00000000}, |
| 502 | 502 | {0x0000989c, 0x00000000, 0x00000000}, |
| 503 | 503 | {0x0000989c, 0x00000000, 0x00000000}, |
| @@ -23,13 +23,13 @@ · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | /* General hardware code for the A5008/AR9001/AR9002 hadware families */ |
| 25 | 25 | |
| 26 | −static void ar9002_hw_init_mode_regs(struct ath_hw *ah) | |
| 26 | +static int ar9002_hw_init_mode_regs(struct ath_hw *ah) | |
| 27 | 27 | { |
| 28 | 28 | if (AR_SREV_9271(ah)) { |
| 29 | 29 | INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271); |
| 30 | 30 | INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271); |
| 31 | 31 | INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg); |
| 32 | − return; | |
| 32 | + return 0; | |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | 35 | if (ah->config.pcie_clock_req) |
| @@ -102,9 +102,9 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) · 66 unmodified lines | ||
| 102 | 102 | u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns; |
| 103 | 103 | u32 *data; |
| 104 | 104 | |
| 105 | − data = kmalloc(size, GFP_KERNEL); | |
| 105 | + data = devm_kzalloc(ah->dev, size, GFP_KERNEL); | |
| 106 | 106 | if (!data) |
| 107 | − return; | |
| 107 | + return -ENOMEM; | |
| 108 | 108 | |
| 109 | 109 | memcpy(data, addac->ia_array, size); |
| 110 | 110 | addac->ia_array = data; |
| @@ -120,6 +120,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) · 9 unmodified lines | ||
| 120 | 120 | INIT_INI_ARRAY(&ah->iniCckfirJapan2484, |
| 121 | 121 | ar9287Common_japan_2484_cck_fir_coeff_9287_1_1); |
| 122 | 122 | } |
| 123 | + return 0; | |
| 123 | 124 | } |
| 124 | 125 | |
| 125 | 126 | static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah) |
| @@ -409,22 +410,30 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah) · 283 unmodified lines | ||
| 409 | 410 | } |
| 410 | 411 | |
| 411 | 412 | /* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */ |
| 412 | −void ar9002_hw_attach_ops(struct ath_hw *ah) | |
| 413 | +int ar9002_hw_attach_ops(struct ath_hw *ah) | |
| 413 | 414 | { |
| 414 | 415 | struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); |
| 415 | 416 | struct ath_hw_ops *ops = ath9k_hw_ops(ah); |
| 417 | + int ret; | |
| 418 | + | |
| 419 | + ret = ar9002_hw_init_mode_regs(ah); | |
| 420 | + if (ret) | |
| 421 | + return ret; | |
| 416 | 422 | |
| 417 | − priv_ops->init_mode_regs = ar9002_hw_init_mode_regs; | |
| 418 | 423 | priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs; |
| 419 | 424 | |
| 420 | 425 | ops->config_pci_powersave = ar9002_hw_configpcipowersave; |
| 421 | 426 | |
| 422 | − ar5008_hw_attach_phy_ops(ah); | |
| 427 | + ret = ar5008_hw_attach_phy_ops(ah); | |
| 428 | + if (ret) | |
| 429 | + return ret; | |
| 430 | + | |
| 423 | 431 | if (AR_SREV_9280_20_OR_LATER(ah)) |
| 424 | 432 | ar9002_hw_attach_phy_ops(ah); |
| 425 | 433 | |
| 426 | 434 | ar9002_hw_attach_calib_ops(ah); |
| 427 | 435 | ar9002_hw_attach_mac_ops(ah); |
| 436 | + return 0; | |
| 428 | 437 | } |
| 429 | 438 | |
| 430 | 439 | void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan) |
| @@ -555,14 +555,73 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah, · 554 unmodified lines | ||
| 555 | 555 | REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); |
| 556 | 556 | } |
| 557 | 557 | |
| 558 | +static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, | |
| 559 | + struct ath_spec_scan *param) | |
| 560 | +{ | |
| 561 | + u8 count; | |
| 562 | + | |
| 563 | + if (!param->enabled) { | |
| 564 | + REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, | |
| 565 | + AR_PHY_SPECTRAL_SCAN_ENABLE); | |
| 566 | + return; | |
| 567 | + } | |
| 568 | + REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA); | |
| 569 | + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); | |
| 570 | + | |
| 571 | + if (param->short_repeat) | |
| 572 | + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, | |
| 573 | + AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); | |
| 574 | + else | |
| 575 | + REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, | |
| 576 | + AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); | |
| 577 | + | |
| 578 | + /* on AR92xx, the highest bit of count will make the the chip send | |
| 579 | + * spectral samples endlessly. Check if this really was intended, | |
| 580 | + * and fix otherwise. | |
| 581 | + */ | |
| 582 | + count = param->count; | |
| 583 | + if (param->endless) | |
| 584 | + count = 0x80; | |
| 585 | + else if (count & 0x80) | |
| 586 | + count = 0x7f; | |
| 587 | + | |
| 588 | + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, | |
| 589 | + AR_PHY_SPECTRAL_SCAN_COUNT, count); | |
| 590 | + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, | |
| 591 | + AR_PHY_SPECTRAL_SCAN_PERIOD, param->period); | |
| 592 | + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, | |
| 593 | + AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period); | |
| 594 | + | |
| 595 | + return; | |
| 596 | +} | |
| 597 | + | |
| 598 | +static void ar9002_hw_spectral_scan_trigger(struct ath_hw *ah) | |
| 599 | +{ | |
| 600 | + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); | |
| 601 | + /* Activate spectral scan */ | |
| 602 | + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, | |
| 603 | + AR_PHY_SPECTRAL_SCAN_ACTIVE); | |
| 604 | +} | |
| 605 | + | |
| 606 | +static void ar9002_hw_spectral_scan_wait(struct ath_hw *ah) | |
| 607 | +{ | |
| 608 | + struct ath_common *common = ath9k_hw_common(ah); | |
| 609 | + | |
| 610 | + /* Poll for spectral scan complete */ | |
| 611 | + if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN, | |
| 612 | + AR_PHY_SPECTRAL_SCAN_ACTIVE, | |
| 613 | + 0, AH_WAIT_TIMEOUT)) { | |
| 614 | + ath_err(common, "spectral scan wait failed\n"); | |
| 615 | + return; | |
| 616 | + } | |
| 617 | +} | |
| 618 | + | |
| 558 | 619 | void ar9002_hw_attach_phy_ops(struct ath_hw *ah) |
| 559 | 620 | { |
| 560 | 621 | struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); |
| 561 | 622 | struct ath_hw_ops *ops = ath9k_hw_ops(ah); |
| 562 | 623 | |
| 563 | 624 | priv_ops->set_rf_regs = NULL; |
| 564 | − priv_ops->rf_alloc_ext_banks = NULL; | |
| 565 | − priv_ops->rf_free_ext_banks = NULL; | |
| 566 | 625 | priv_ops->rf_set_freq = ar9002_hw_set_channel; |
| 567 | 626 | priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate; |
| 568 | 627 | priv_ops->olc_init = ar9002_olc_init; |
| @@ -571,6 +630,9 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah) · 2 unmodified lines | ||
| 571 | 630 | |
| 572 | 631 | ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get; |
| 573 | 632 | ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set; |
| 633 | + ops->spectral_scan_config = ar9002_hw_spectral_scan_config; | |
| 634 | + ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger; | |
| 635 | + ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait; | |
| 574 | 636 | |
| 575 | 637 | ar9002_hw_set_nf_limits(ah); |
| 576 | 638 | } |
| @@ -744,6 +744,186 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { · 743 unmodified lines | ||
| 744 | 744 | {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, |
| 745 | 745 | }; |
| 746 | 746 | |
| 747 | +static const u32 ar9300Modes_mixed_ob_db_tx_gain_table_2p2[][5] = { | |
| 748 | + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | |
| 749 | + {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, | |
| 750 | + {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, | |
| 751 | + {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, | |
| 752 | + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | |
| 753 | + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, | |
| 754 | + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 755 | + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, | |
| 756 | + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, | |
| 757 | + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, | |
| 758 | + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, | |
| 759 | + {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400}, | |
| 760 | + {0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402}, | |
| 761 | + {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, | |
| 762 | + {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603}, | |
| 763 | + {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02}, | |
| 764 | + {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04}, | |
| 765 | + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20}, | |
| 766 | + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20}, | |
| 767 | + {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22}, | |
| 768 | + {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24}, | |
| 769 | + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640}, | |
| 770 | + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660}, | |
| 771 | + {0x0000a544, 0x52022470, 0x52022470, 0x3b001861, 0x3b001861}, | |
| 772 | + {0x0000a548, 0x55022490, 0x55022490, 0x3e001a81, 0x3e001a81}, | |
| 773 | + {0x0000a54c, 0x59022492, 0x59022492, 0x42001a83, 0x42001a83}, | |
| 774 | + {0x0000a550, 0x5d022692, 0x5d022692, 0x44001c84, 0x44001c84}, | |
| 775 | + {0x0000a554, 0x61022892, 0x61022892, 0x48001ce3, 0x48001ce3}, | |
| 776 | + {0x0000a558, 0x65024890, 0x65024890, 0x4c001ce5, 0x4c001ce5}, | |
| 777 | + {0x0000a55c, 0x69024892, 0x69024892, 0x50001ce9, 0x50001ce9}, | |
| 778 | + {0x0000a560, 0x6e024c92, 0x6e024c92, 0x54001ceb, 0x54001ceb}, | |
| 779 | + {0x0000a564, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, | |
| 780 | + {0x0000a568, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, | |
| 781 | + {0x0000a56c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, | |
| 782 | + {0x0000a570, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, | |
| 783 | + {0x0000a574, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, | |
| 784 | + {0x0000a578, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, | |
| 785 | + {0x0000a57c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, | |
| 786 | + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, | |
| 787 | + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, | |
| 788 | + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, | |
| 789 | + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, | |
| 790 | + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, | |
| 791 | + {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400}, | |
| 792 | + {0x0000a598, 0x21802220, 0x21802220, 0x15800402, 0x15800402}, | |
| 793 | + {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, | |
| 794 | + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603}, | |
| 795 | + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02}, | |
| 796 | + {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04}, | |
| 797 | + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20}, | |
| 798 | + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20}, | |
| 799 | + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22}, | |
| 800 | + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24}, | |
| 801 | + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640}, | |
| 802 | + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660}, | |
| 803 | + {0x0000a5c4, 0x52822470, 0x52822470, 0x3b801861, 0x3b801861}, | |
| 804 | + {0x0000a5c8, 0x55822490, 0x55822490, 0x3e801a81, 0x3e801a81}, | |
| 805 | + {0x0000a5cc, 0x59822492, 0x59822492, 0x42801a83, 0x42801a83}, | |
| 806 | + {0x0000a5d0, 0x5d822692, 0x5d822692, 0x44801c84, 0x44801c84}, | |
| 807 | + {0x0000a5d4, 0x61822892, 0x61822892, 0x48801ce3, 0x48801ce3}, | |
| 808 | + {0x0000a5d8, 0x65824890, 0x65824890, 0x4c801ce5, 0x4c801ce5}, | |
| 809 | + {0x0000a5dc, 0x69824892, 0x69824892, 0x50801ce9, 0x50801ce9}, | |
| 810 | + {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x54801ceb, 0x54801ceb}, | |
| 811 | + {0x0000a5e4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, | |
| 812 | + {0x0000a5e8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, | |
| 813 | + {0x0000a5ec, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, | |
| 814 | + {0x0000a5f0, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, | |
| 815 | + {0x0000a5f4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, | |
| 816 | + {0x0000a5f8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, | |
| 817 | + {0x0000a5fc, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, | |
| 818 | + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 819 | + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 820 | + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 821 | + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 822 | + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 823 | + {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000}, | |
| 824 | + {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501}, | |
| 825 | + {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501}, | |
| 826 | + {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03}, | |
| 827 | + {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04}, | |
| 828 | + {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04}, | |
| 829 | + {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, | |
| 830 | + {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, | |
| 831 | + {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, | |
| 832 | + {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, | |
| 833 | + {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, | |
| 834 | + {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, | |
| 835 | + {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, | |
| 836 | + {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, | |
| 837 | + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | |
| 838 | + {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, | |
| 839 | + {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, | |
| 840 | + {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, | |
| 841 | + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | |
| 842 | + {0x00016044, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4}, | |
| 843 | + {0x00016048, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001}, | |
| 844 | + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, | |
| 845 | + {0x00016444, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4}, | |
| 846 | + {0x00016448, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001}, | |
| 847 | + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, | |
| 848 | + {0x00016844, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4}, | |
| 849 | + {0x00016848, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001}, | |
| 850 | + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, | |
| 851 | +}; | |
| 852 | + | |
| 853 | +static const u32 ar9300Modes_type5_tx_gain_table_2p2[][5] = { | |
| 854 | + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | |
| 855 | + {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, | |
| 856 | + {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, | |
| 857 | + {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, | |
| 858 | + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | |
| 859 | + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, | |
| 860 | + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 861 | + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, | |
| 862 | + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, | |
| 863 | + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, | |
| 864 | + {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, | |
| 865 | + {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, | |
| 866 | + {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, | |
| 867 | + {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, | |
| 868 | + {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, | |
| 869 | + {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, | |
| 870 | + {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, | |
| 871 | + {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, | |
| 872 | + {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, | |
| 873 | + {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, | |
| 874 | + {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, | |
| 875 | + {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, | |
| 876 | + {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, | |
| 877 | + {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, | |
| 878 | + {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, | |
| 879 | + {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83}, | |
| 880 | + {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84}, | |
| 881 | + {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, | |
| 882 | + {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, | |
| 883 | + {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, | |
| 884 | + {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, | |
| 885 | + {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 886 | + {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 887 | + {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 888 | + {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 889 | + {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 890 | + {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 891 | + {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 892 | + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 893 | + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 894 | + {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, | |
| 895 | + {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, | |
| 896 | + {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, | |
| 897 | + {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, | |
| 898 | + {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, | |
| 899 | + {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, | |
| 900 | + {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, | |
| 901 | + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, | |
| 902 | + {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, | |
| 903 | + {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, | |
| 904 | + {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, | |
| 905 | + {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, | |
| 906 | + {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, | |
| 907 | + {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, | |
| 908 | + {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, | |
| 909 | + {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, | |
| 910 | + {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, | |
| 911 | + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | |
| 912 | + {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, | |
| 913 | + {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, | |
| 914 | + {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, | |
| 915 | + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | |
| 916 | + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, | |
| 917 | + {0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, | |
| 918 | + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, | |
| 919 | + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, | |
| 920 | + {0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, | |
| 921 | + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, | |
| 922 | + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, | |
| 923 | + {0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, | |
| 924 | + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, | |
| 925 | +}; | |
| 926 | + | |
| 747 | 927 | static const u32 ar9300Common_rx_gain_table_2p2[][2] = { |
| 748 | 928 | /* Addr allmodes */ |
| 749 | 929 | {0x0000a000, 0x00010000}, |
| @@ -32,7 +32,6 @@ struct coeff { · 31 unmodified lines | ||
| 32 | 32 | |
| 33 | 33 | enum ar9003_cal_types { |
| 34 | 34 | IQ_MISMATCH_CAL = BIT(0), |
| 35 | − TEMP_COMP_CAL = BIT(1), | |
| 36 | 35 | }; |
| 37 | 36 | |
| 38 | 37 | static void ar9003_hw_setup_calibration(struct ath_hw *ah, |
| @@ -49,7 +48,7 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah, · 10 unmodified lines | ||
| 49 | 48 | */ |
| 50 | 49 | REG_RMW_FIELD(ah, AR_PHY_TIMING4, |
| 51 | 50 | AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX, |
| 52 | − currCal->calData->calCountMax); | |
| 51 | + currCal->calData->calCountMax); | |
| 53 | 52 | REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); |
| 54 | 53 | |
| 55 | 54 | ath_dbg(common, CALIBRATE, |
| @@ -58,14 +57,8 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah, · 2 unmodified lines | ||
| 58 | 57 | /* Kick-off cal */ |
| 59 | 58 | REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); |
| 60 | 59 | break; |
| 61 | − case TEMP_COMP_CAL: | |
| 62 | − REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, | |
| 63 | − AR_PHY_65NM_CH0_THERM_LOCAL, 1); | |
| 64 | − REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, | |
| 65 | − AR_PHY_65NM_CH0_THERM_START, 1); | |
| 66 | − | |
| 67 | − ath_dbg(common, CALIBRATE, | |
| 68 | − "starting Temperature Compensation Calibration\n"); | |
| 60 | + default: | |
| 61 | + ath_err(common, "Invalid calibration type\n"); | |
| 69 | 62 | break; |
| 70 | 63 | } |
| 71 | 64 | } |
| @@ -323,6 +316,14 @@ static const struct ath9k_percal_data iq_cal_single_sample = { · 251 unmodified lines | ||
| 323 | 316 | static void ar9003_hw_init_cal_settings(struct ath_hw *ah) |
| 324 | 317 | { |
| 325 | 318 | ah->iq_caldata.calData = &iq_cal_single_sample; |
| 319 | + | |
| 320 | + if (AR_SREV_9300_20_OR_LATER(ah)) { | |
| 321 | + ah->enabled_cals |= TX_IQ_CAL; | |
| 322 | + if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah)) | |
| 323 | + ah->enabled_cals |= TX_IQ_ON_AGC_CAL; | |
| 324 | + } | |
| 325 | + | |
| 326 | + ah->supp_cals = IQ_MISMATCH_CAL; | |
| 326 | 327 | } |
| 327 | 328 | |
| 328 | 329 | /* |
| @@ -959,22 +960,70 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) · 630 unmodified lines | ||
| 959 | 960 | AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0); |
| 960 | 961 | } |
| 961 | 962 | |
| 963 | +static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah, | |
| 964 | + struct ath9k_channel *chan) | |
| 965 | +{ | |
| 966 | + int i; | |
| 967 | + | |
| 968 | + if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah)) | |
| 969 | + return; | |
| 970 | + | |
| 971 | + for (i = 0; i < AR9300_MAX_CHAINS; i++) { | |
| 972 | + if (!(ah->rxchainmask & (1 << i))) | |
| 973 | + continue; | |
| 974 | + ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan)); | |
| 975 | + } | |
| 976 | +} | |
| 977 | + | |
| 978 | +static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable) | |
| 979 | +{ | |
| 980 | + u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0, | |
| 981 | + AR_PHY_CL_TAB_1, | |
| 982 | + AR_PHY_CL_TAB_2 }; | |
| 983 | + struct ath9k_hw_cal_data *caldata = ah->caldata; | |
| 984 | + bool txclcal_done = false; | |
| 985 | + int i, j; | |
| 986 | + | |
| 987 | + if (!caldata || !(ah->enabled_cals & TX_CL_CAL)) | |
| 988 | + return; | |
| 989 | + | |
| 990 | + txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & | |
| 991 | + AR_PHY_AGC_CONTROL_CLC_SUCCESS); | |
| 992 | + | |
| 993 | + if (caldata->done_txclcal_once) { | |
| 994 | + for (i = 0; i < AR9300_MAX_CHAINS; i++) { | |
| 995 | + if (!(ah->txchainmask & (1 << i))) | |
| 996 | + continue; | |
| 997 | + for (j = 0; j < MAX_CL_TAB_ENTRY; j++) | |
| 998 | + REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]), | |
| 999 | + caldata->tx_clcal[i][j]); | |
| 1000 | + } | |
| 1001 | + } else if (is_reusable && txclcal_done) { | |
| 1002 | + for (i = 0; i < AR9300_MAX_CHAINS; i++) { | |
| 1003 | + if (!(ah->txchainmask & (1 << i))) | |
| 1004 | + continue; | |
| 1005 | + for (j = 0; j < MAX_CL_TAB_ENTRY; j++) | |
| 1006 | + caldata->tx_clcal[i][j] = | |
| 1007 | + REG_READ(ah, CL_TAB_ENTRY(cl_idx[i])); | |
| 1008 | + } | |
| 1009 | + caldata->done_txclcal_once = true; | |
| 1010 | + } | |
| 1011 | +} | |
| 1012 | + | |
| 962 | 1013 | static bool ar9003_hw_init_cal(struct ath_hw *ah, |
| 963 | 1014 | struct ath9k_channel *chan) |
| 964 | 1015 | { |
| 965 | 1016 | struct ath_common *common = ath9k_hw_common(ah); |
| 966 | 1017 | struct ath9k_hw_cal_data *caldata = ah->caldata; |
| 967 | − bool txiqcal_done = false, txclcal_done = false; | |
| 1018 | + bool txiqcal_done = false; | |
| 968 | 1019 | bool is_reusable = true, status = true; |
| 969 | − bool run_rtt_cal = false, run_agc_cal; | |
| 1020 | + bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false; | |
| 970 | 1021 | bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); |
| 971 | 1022 | u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL | |
| 972 | 1023 | AR_PHY_AGC_CONTROL_FLTR_CAL | |
| 973 | 1024 | AR_PHY_AGC_CONTROL_PKDET_CAL; |
| 974 | − int i, j; | |
| 975 | − u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0, | |
| 976 | − AR_PHY_CL_TAB_1, | |
| 977 | − AR_PHY_CL_TAB_2 }; | |
| 1025 | + | |
| 1026 | + ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); | |
| 978 | 1027 | |
| 979 | 1028 | if (rtt) { |
| 980 | 1029 | if (!ar9003_hw_rtt_restore(ah, chan)) |
| @@ -1012,7 +1061,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, · 31 unmodified lines | ||
| 1012 | 1061 | } |
| 1013 | 1062 | } |
| 1014 | 1063 | |
| 1015 | − if (!(ah->enabled_cals & TX_IQ_CAL)) | |
| 1064 | + if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) || | |
| 1065 | + !(ah->enabled_cals & TX_IQ_CAL)) | |
| 1016 | 1066 | goto skip_tx_iqcal; |
| 1017 | 1067 | |
| 1018 | 1068 | /* Do Tx IQ Calibration */ |
| @@ -1032,21 +1082,22 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, · 13 unmodified lines | ||
| 1032 | 1082 | REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, |
| 1033 | 1083 | AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); |
| 1034 | 1084 | txiqcal_done = run_agc_cal = true; |
| 1035 | − goto skip_tx_iqcal; | |
| 1036 | − } else if (caldata && !caldata->done_txiqcal_once) | |
| 1085 | + } else if (caldata && !caldata->done_txiqcal_once) { | |
| 1037 | 1086 | run_agc_cal = true; |
| 1087 | + sep_iq_cal = true; | |
| 1088 | + } | |
| 1038 | 1089 | |
| 1090 | +skip_tx_iqcal: | |
| 1039 | 1091 | if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) |
| 1040 | 1092 | ar9003_mci_init_cal_req(ah, &is_reusable); |
| 1041 | 1093 | |
| 1042 | − if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) { | |
| 1094 | + if (sep_iq_cal) { | |
| 1043 | 1095 | txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); |
| 1044 | 1096 | REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); |
| 1045 | 1097 | udelay(5); |
| 1046 | 1098 | REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); |
| 1047 | 1099 | } |
| 1048 | 1100 | |
| 1049 | −skip_tx_iqcal: | |
| 1050 | 1101 | if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { |
| 1051 | 1102 | /* Calibrate the AGC */ |
| 1052 | 1103 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, |
| @@ -1057,14 +1108,8 @@ skip_tx_iqcal: · 4 unmodified lines | ||
| 1057 | 1108 | status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, |
| 1058 | 1109 | AR_PHY_AGC_CONTROL_CAL, |
| 1059 | 1110 | 0, AH_WAIT_TIMEOUT); |
| 1060 | − if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { | |
| 1061 | − for (i = 0; i < AR9300_MAX_CHAINS; i++) { | |
| 1062 | − if (!(ah->rxchainmask & (1 << i))) | |
| 1063 | − continue; | |
| 1064 | − ar9003_hw_manual_peak_cal(ah, i, | |
| 1065 | − IS_CHAN_2GHZ(chan)); | |
| 1066 | − } | |
| 1067 | − } | |
| 1111 | + | |
| 1112 | + ar9003_hw_do_manual_peak_cal(ah, chan); | |
| 1068 | 1113 | } |
| 1069 | 1114 | |
| 1070 | 1115 | if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) |
| @@ -1089,31 +1134,7 @@ skip_tx_iqcal: · 18 unmodified lines | ||
| 1089 | 1134 | else if (caldata && caldata->done_txiqcal_once) |
| 1090 | 1135 | ar9003_hw_tx_iq_cal_reload(ah); |
| 1091 | 1136 | |
| 1092 | −#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j)) | |
| 1093 | − if (caldata && (ah->enabled_cals & TX_CL_CAL)) { | |
| 1094 | − txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & | |
| 1095 | − AR_PHY_AGC_CONTROL_CLC_SUCCESS); | |
| 1096 | − if (caldata->done_txclcal_once) { | |
| 1097 | − for (i = 0; i < AR9300_MAX_CHAINS; i++) { | |
| 1098 | − if (!(ah->txchainmask & (1 << i))) | |
| 1099 | − continue; | |
| 1100 | − for (j = 0; j < MAX_CL_TAB_ENTRY; j++) | |
| 1101 | − REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]), | |
| 1102 | − caldata->tx_clcal[i][j]); | |
| 1103 | − } | |
| 1104 | − } else if (is_reusable && txclcal_done) { | |
| 1105 | − for (i = 0; i < AR9300_MAX_CHAINS; i++) { | |
| 1106 | − if (!(ah->txchainmask & (1 << i))) | |
| 1107 | − continue; | |
| 1108 | − for (j = 0; j < MAX_CL_TAB_ENTRY; j++) | |
| 1109 | − caldata->tx_clcal[i][j] = | |
| 1110 | − REG_READ(ah, | |
| 1111 | − CL_TAB_ENTRY(cl_idx[i])); | |
| 1112 | − } | |
| 1113 | − caldata->done_txclcal_once = true; | |
| 1114 | − } | |
| 1115 | − } | |
| 1116 | −#undef CL_TAB_ENTRY | |
| 1137 | + ar9003_hw_cl_cal_post_proc(ah, is_reusable); | |
| 1117 | 1138 | |
| 1118 | 1139 | if (run_rtt_cal && caldata) { |
| 1119 | 1140 | if (is_reusable) { |
| @@ -1131,20 +1152,10 @@ skip_tx_iqcal: · 11 unmodified lines | ||
| 1131 | 1152 | |
| 1132 | 1153 | /* Initialize list pointers */ |
| 1133 | 1154 | ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; |
| 1134 | − ah->supp_cals = IQ_MISMATCH_CAL; | |
| 1135 | − | |
| 1136 | − if (ah->supp_cals & IQ_MISMATCH_CAL) { | |
| 1137 | − INIT_CAL(&ah->iq_caldata); | |
| 1138 | − INSERT_CAL(ah, &ah->iq_caldata); | |
| 1139 | − ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); | |
| 1140 | − } | |
| 1141 | 1155 | |
| 1142 | − if (ah->supp_cals & TEMP_COMP_CAL) { | |
| 1143 | − INIT_CAL(&ah->tempCompCalData); | |
| 1144 | − INSERT_CAL(ah, &ah->tempCompCalData); | |
| 1145 | − ath_dbg(common, CALIBRATE, | |
| 1146 | − "enabling Temperature Compensation Calibration\n"); | |
| 1147 | − } | |
| 1156 | + INIT_CAL(&ah->iq_caldata); | |
| 1157 | + INSERT_CAL(ah, &ah->iq_caldata); | |
| 1158 | + ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); | |
| 1148 | 1159 | |
| 1149 | 1160 | /* Initialize current pointer to first element in list */ |
| 1150 | 1161 | ah->cal_list_curr = ah->cal_list; |
| @@ -4586,14 +4586,14 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, · 4585 unmodified lines | ||
| 4586 | 4586 | return 0; |
| 4587 | 4587 | } |
| 4588 | 4588 | |
| 4589 | −static int ar9003_hw_power_control_override(struct ath_hw *ah, | |
| 4590 | − int frequency, | |
| 4591 | − int *correction, | |
| 4592 | − int *voltage, int *temperature) | |
| 4589 | +static void ar9003_hw_power_control_override(struct ath_hw *ah, | |
| 4590 | + int frequency, | |
| 4591 | + int *correction, | |
| 4592 | + int *voltage, int *temperature) | |
| 4593 | 4593 | { |
| 4594 | − int tempSlope = 0; | |
| 4594 | + int temp_slope = 0, temp_slope1 = 0, temp_slope2 = 0; | |
| 4595 | 4595 | struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; |
| 4596 | − int f[8], t[8], i; | |
| 4596 | + int f[8], t[8], t1[3], t2[3], i; | |
| 4597 | 4597 | |
| 4598 | 4598 | REG_RMW(ah, AR_PHY_TPC_11_B0, |
| 4599 | 4599 | (correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), |
| @@ -4624,38 +4624,108 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah, · 24 unmodified lines | ||
| 4624 | 4624 | * enable temperature compensation |
| 4625 | 4625 | * Need to use register names |
| 4626 | 4626 | */ |
| 4627 | − if (frequency < 4000) | |
| 4628 | − tempSlope = eep->modalHeader2G.tempSlope; | |
| 4629 | − else if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) { | |
| 4630 | − for (i = 0; i < 8; i++) { | |
| 4631 | − t[i] = eep->base_ext1.tempslopextension[i]; | |
| 4632 | − f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0); | |
| 4627 | + if (frequency < 4000) { | |
| 4628 | + temp_slope = eep->modalHeader2G.tempSlope; | |
| 4629 | + } else { | |
| 4630 | + if (AR_SREV_9550(ah)) { | |
| 4631 | + t[0] = eep->base_ext1.tempslopextension[2]; | |
| 4632 | + t1[0] = eep->base_ext1.tempslopextension[3]; | |
| 4633 | + t2[0] = eep->base_ext1.tempslopextension[4]; | |
| 4634 | + f[0] = 5180; | |
| 4635 | + | |
| 4636 | + t[1] = eep->modalHeader5G.tempSlope; | |
| 4637 | + t1[1] = eep->base_ext1.tempslopextension[0]; | |
| 4638 | + t2[1] = eep->base_ext1.tempslopextension[1]; | |
| 4639 | + f[1] = 5500; | |
| 4640 | + | |
| 4641 | + t[2] = eep->base_ext1.tempslopextension[5]; | |
| 4642 | + t1[2] = eep->base_ext1.tempslopextension[6]; | |
| 4643 | + t2[2] = eep->base_ext1.tempslopextension[7]; | |
| 4644 | + f[2] = 5785; | |
| 4645 | + | |
| 4646 | + temp_slope = ar9003_hw_power_interpolate(frequency, | |
| 4647 | + f, t, 3); | |
| 4648 | + temp_slope1 = ar9003_hw_power_interpolate(frequency, | |
| 4649 | + f, t1, 3); | |
| 4650 | + temp_slope2 = ar9003_hw_power_interpolate(frequency, | |
| 4651 | + f, t2, 3); | |
| 4652 | + | |
| 4653 | + goto tempslope; | |
| 4633 | 4654 | } |
| 4634 | − tempSlope = ar9003_hw_power_interpolate((s32) frequency, | |
| 4635 | − f, t, 8); | |
| 4636 | − } else if (eep->base_ext2.tempSlopeLow != 0) { | |
| 4637 | − t[0] = eep->base_ext2.tempSlopeLow; | |
| 4638 | − f[0] = 5180; | |
| 4639 | − t[1] = eep->modalHeader5G.tempSlope; | |
| 4640 | − f[1] = 5500; | |
| 4641 | − t[2] = eep->base_ext2.tempSlopeHigh; | |
| 4642 | − f[2] = 5785; | |
| 4643 | − tempSlope = ar9003_hw_power_interpolate((s32) frequency, | |
| 4644 | − f, t, 3); | |
| 4645 | − } else | |
| 4646 | − tempSlope = eep->modalHeader5G.tempSlope; | |
| 4647 | 4655 | |
| 4648 | − REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope); | |
| 4656 | + if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) { | |
| 4657 | + for (i = 0; i < 8; i++) { | |
| 4658 | + t[i] = eep->base_ext1.tempslopextension[i]; | |
| 4659 | + f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0); | |
| 4660 | + } | |
| 4661 | + temp_slope = ar9003_hw_power_interpolate((s32) frequency, | |
| 4662 | + f, t, 8); | |
| 4663 | + } else if (eep->base_ext2.tempSlopeLow != 0) { | |
| 4664 | + t[0] = eep->base_ext2.tempSlopeLow; | |
| 4665 | + f[0] = 5180; | |
| 4666 | + t[1] = eep->modalHeader5G.tempSlope; | |
| 4667 | + f[1] = 5500; | |
| 4668 | + t[2] = eep->base_ext2.tempSlopeHigh; | |
| 4669 | + f[2] = 5785; | |
| 4670 | + temp_slope = ar9003_hw_power_interpolate((s32) frequency, | |
| 4671 | + f, t, 3); | |
| 4672 | + } else { | |
| 4673 | + temp_slope = eep->modalHeader5G.tempSlope; | |
| 4674 | + } | |
| 4675 | + } | |
| 4676 | + | |
| 4677 | +tempslope: | |
| 4678 | + if (AR_SREV_9550(ah)) { | |
| 4679 | + /* | |
| 4680 | + * AR955x has tempSlope register for each chain. | |
| 4681 | + * Check whether temp_compensation feature is enabled or not. | |
| 4682 | + */ | |
| 4683 | + if (eep->baseEepHeader.featureEnable & 0x1) { | |
| 4684 | + if (frequency < 4000) { | |
| 4685 | + REG_RMW_FIELD(ah, AR_PHY_TPC_19, | |
| 4686 | + AR_PHY_TPC_19_ALPHA_THERM, | |
| 4687 | + eep->base_ext2.tempSlopeLow); | |
| 4688 | + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, | |
| 4689 | + AR_PHY_TPC_19_ALPHA_THERM, | |
| 4690 | + temp_slope); | |
| 4691 | + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, | |
| 4692 | + AR_PHY_TPC_19_ALPHA_THERM, | |
| 4693 | + eep->base_ext2.tempSlopeHigh); | |
| 4694 | + } else { | |
| 4695 | + REG_RMW_FIELD(ah, AR_PHY_TPC_19, | |
| 4696 | + AR_PHY_TPC_19_ALPHA_THERM, | |
| 4697 | + temp_slope); | |
| 4698 | + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, | |
| 4699 | + AR_PHY_TPC_19_ALPHA_THERM, | |
| 4700 | + temp_slope1); | |
| 4701 | + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, | |
| 4702 | + AR_PHY_TPC_19_ALPHA_THERM, | |
| 4703 | + temp_slope2); | |
| 4704 | + } | |
| 4705 | + } else { | |
| 4706 | + /* | |
| 4707 | + * If temp compensation is not enabled, | |
| 4708 | + * set all registers to 0. | |
| 4709 | + */ | |
| 4710 | + REG_RMW_FIELD(ah, AR_PHY_TPC_19, | |
| 4711 | + AR_PHY_TPC_19_ALPHA_THERM, 0); | |
| 4712 | + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, | |
| 4713 | + AR_PHY_TPC_19_ALPHA_THERM, 0); | |
| 4714 | + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, | |
| 4715 | + AR_PHY_TPC_19_ALPHA_THERM, 0); | |
| 4716 | + } | |
| 4717 | + } else { | |
| 4718 | + REG_RMW_FIELD(ah, AR_PHY_TPC_19, | |
| 4719 | + AR_PHY_TPC_19_ALPHA_THERM, temp_slope); | |
| 4720 | + } | |
| 4649 | 4721 | |
| 4650 | 4722 | if (AR_SREV_9462_20(ah)) |
| 4651 | 4723 | REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, |
| 4652 | − AR_PHY_TPC_19_B1_ALPHA_THERM, tempSlope); | |
| 4724 | + AR_PHY_TPC_19_B1_ALPHA_THERM, temp_slope); | |
| 4653 | 4725 | |
| 4654 | 4726 | |
| 4655 | 4727 | REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE, |
| 4656 | 4728 | temperature[0]); |
| 4657 | − | |
| 4658 | − return 0; | |
| 4659 | 4729 | } |
| 4660 | 4730 | |
| 4661 | 4731 | /* Apply the recorded correction values. */ |
| @@ -507,28 +507,59 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) · 506 unmodified lines | ||
| 507 | 507 | else if (AR_SREV_9580(ah)) |
| 508 | 508 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
| 509 | 509 | ar9580_1p0_mixed_ob_db_tx_gain_table); |
| 510 | + else | |
| 511 | + INIT_INI_ARRAY(&ah->iniModesTxGain, | |
| 512 | + ar9300Modes_mixed_ob_db_tx_gain_table_2p2); | |
| 513 | +} | |
| 514 | + | |
| 515 | +static void ar9003_tx_gain_table_mode5(struct ath_hw *ah) | |
| 516 | +{ | |
| 517 | + if (AR_SREV_9485_11(ah)) | |
| 518 | + INIT_INI_ARRAY(&ah->iniModesTxGain, | |
| 519 | + ar9485Modes_green_ob_db_tx_gain_1_1); | |
| 520 | + else if (AR_SREV_9340(ah)) | |
| 521 | + INIT_INI_ARRAY(&ah->iniModesTxGain, | |
| 522 | + ar9340Modes_ub124_tx_gain_table_1p0); | |
| 523 | + else if (AR_SREV_9580(ah)) | |
| 524 | + INIT_INI_ARRAY(&ah->iniModesTxGain, | |
| 525 | + ar9580_1p0_type5_tx_gain_table); | |
| 526 | + else if (AR_SREV_9300_22(ah)) | |
| 527 | + INIT_INI_ARRAY(&ah->iniModesTxGain, | |
| 528 | + ar9300Modes_type5_tx_gain_table_2p2); | |
| 529 | +} | |
| 530 | + | |
| 531 | +static void ar9003_tx_gain_table_mode6(struct ath_hw *ah) | |
| 532 | +{ | |
| 533 | + if (AR_SREV_9340(ah)) | |
| 534 | + INIT_INI_ARRAY(&ah->iniModesTxGain, | |
| 535 | + ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0); | |
| 536 | + else if (AR_SREV_9485_11(ah)) | |
| 537 | + INIT_INI_ARRAY(&ah->iniModesTxGain, | |
| 538 | + ar9485Modes_green_spur_ob_db_tx_gain_1_1); | |
| 539 | + else if (AR_SREV_9580(ah)) | |
| 540 | + INIT_INI_ARRAY(&ah->iniModesTxGain, | |
| 541 | + ar9580_1p0_type6_tx_gain_table); | |
| 510 | 542 | } |
| 511 | 543 | |
| 544 | +typedef void (*ath_txgain_tab)(struct ath_hw *ah); | |
| 545 | + | |
| 512 | 546 | static void ar9003_tx_gain_table_apply(struct ath_hw *ah) |
| 513 | 547 | { |
| 514 | − switch (ar9003_hw_get_tx_gain_idx(ah)) { | |
| 515 | − case 0: | |
| 516 | − default: | |
| 517 | − ar9003_tx_gain_table_mode0(ah); | |
| 518 | − break; | |
| 519 | − case 1: | |
| 520 | − ar9003_tx_gain_table_mode1(ah); | |
| 521 | − break; | |
| 522 | − case 2: | |
| 523 | − ar9003_tx_gain_table_mode2(ah); | |
| 524 | − break; | |
| 525 | − case 3: | |
| 526 | − ar9003_tx_gain_table_mode3(ah); | |
| 527 | − break; | |
| 528 | − case 4: | |
| 529 | − ar9003_tx_gain_table_mode4(ah); | |
| 530 | − break; | |
| 531 | − } | |
| 548 | + static const ath_txgain_tab modes[] = { | |
| 549 | + ar9003_tx_gain_table_mode0, | |
| 550 | + ar9003_tx_gain_table_mode1, | |
| 551 | + ar9003_tx_gain_table_mode2, | |
| 552 | + ar9003_tx_gain_table_mode3, | |
| 553 | + ar9003_tx_gain_table_mode4, | |
| 554 | + ar9003_tx_gain_table_mode5, | |
| 555 | + ar9003_tx_gain_table_mode6, | |
| 556 | + }; | |
| 557 | + int idx = ar9003_hw_get_tx_gain_idx(ah); | |
| 558 | + | |
| 559 | + if (idx >= ARRAY_SIZE(modes)) | |
| 560 | + idx = 0; | |
| 561 | + | |
| 562 | + modes[idx](ah); | |
| 532 | 563 | } |
| 533 | 564 | |
| 534 | 565 | static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) |
| @@ -544,7 +575,7 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) · 9 unmodified lines | ||
| 544 | 575 | ar9340Common_rx_gain_table_1p0); |
| 545 | 576 | else if (AR_SREV_9485_11(ah)) |
| 546 | 577 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
| 547 | − ar9485Common_wo_xlna_rx_gain_1_1); | |
| 578 | + ar9485_common_rx_gain_1_1); | |
| 548 | 579 | else if (AR_SREV_9550(ah)) { |
| 549 | 580 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
| 550 | 581 | ar955x_1p0_common_rx_gain_table); |
| @@ -673,7 +704,7 @@ void ar9003_hw_attach_ops(struct ath_hw *ah) · 122 unmodified lines | ||
| 673 | 704 | struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); |
| 674 | 705 | struct ath_hw_ops *ops = ath9k_hw_ops(ah); |
| 675 | 706 | |
| 676 | − priv_ops->init_mode_regs = ar9003_hw_init_mode_regs; | |
| 707 | + ar9003_hw_init_mode_regs(ah); | |
| 677 | 708 | priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs; |
| 678 | 709 | |
| 679 | 710 | ops->config_pci_powersave = ar9003_hw_configpcipowersave; |
| @@ -68,7 +68,7 @@ static const int m2ThreshExt_off = 127; · 67 unmodified lines | ||
| 68 | 68 | static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) |
| 69 | 69 | { |
| 70 | 70 | u16 bMode, fracMode = 0, aModeRefSel = 0; |
| 71 | − u32 freq, channelSel = 0, reg32 = 0; | |
| 71 | + u32 freq, chan_frac, div, channelSel = 0, reg32 = 0; | |
| 72 | 72 | struct chan_centers centers; |
| 73 | 73 | int loadSynthChannel; |
| 74 | 74 | |
| @@ -77,9 +77,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) · 2 unmodified lines | ||
| 77 | 77 | |
| 78 | 78 | if (freq < 4800) { /* 2 GHz, fractional mode */ |
| 79 | 79 | if (AR_SREV_9330(ah)) { |
| 80 | − u32 chan_frac; | |
| 81 | − u32 div; | |
| 82 | − | |
| 83 | 80 | if (ah->is_clk_25mhz) |
| 84 | 81 | div = 75; |
| 85 | 82 | else |
| @@ -89,34 +86,40 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) · 3 unmodified lines | ||
| 89 | 86 | chan_frac = (((freq * 4) % div) * 0x20000) / div; |
| 90 | 87 | channelSel = (channelSel << 17) | chan_frac; |
| 91 | 88 | } else if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) { |
| 92 | − u32 chan_frac; | |
| 93 | − | |
| 94 | 89 | /* |
| 95 | − * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0 | |
| 90 | + * freq_ref = 40 / (refdiva >> amoderefsel); | |
| 91 | + * where refdiva=1 and amoderefsel=0 | |
| 96 | 92 | * ndiv = ((chan_mhz * 4) / 3) / freq_ref; |
| 97 | 93 | * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 |
| 98 | 94 | */ |
| 99 | 95 | channelSel = (freq * 4) / 120; |
| 100 | 96 | chan_frac = (((freq * 4) % 120) * 0x20000) / 120; |
| 101 | 97 | channelSel = (channelSel << 17) | chan_frac; |
| 102 | − } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { | |
| 98 | + } else if (AR_SREV_9340(ah)) { | |
| 103 | 99 | if (ah->is_clk_25mhz) { |
| 104 | − u32 chan_frac; | |
| 105 | − | |
| 106 | 100 | channelSel = (freq * 2) / 75; |
| 107 | 101 | chan_frac = (((freq * 2) % 75) * 0x20000) / 75; |
| 108 | 102 | channelSel = (channelSel << 17) | chan_frac; |
| 109 | − } else | |
| 103 | + } else { | |
| 110 | 104 | channelSel = CHANSEL_2G(freq) >> 1; |
| 111 | − } else | |
| 105 | + } | |
| 106 | + } else if (AR_SREV_9550(ah)) { | |
| 107 | + if (ah->is_clk_25mhz) | |
| 108 | + div = 75; | |
| 109 | + else | |
| 110 | + div = 120; | |
| 111 | + | |
| 112 | + channelSel = (freq * 4) / div; | |
| 113 | + chan_frac = (((freq * 4) % div) * 0x20000) / div; | |
| 114 | + channelSel = (channelSel << 17) | chan_frac; | |
| 115 | + } else { | |
| 112 | 116 | channelSel = CHANSEL_2G(freq); |
| 117 | + } | |
| 113 | 118 | /* Set to 2G mode */ |
| 114 | 119 | bMode = 1; |
| 115 | 120 | } else { |
| 116 | 121 | if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) && |
| 117 | 122 | ah->is_clk_25mhz) { |
| 118 | − u32 chan_frac; | |
| 119 | − | |
| 120 | 123 | channelSel = freq / 75; |
| 121 | 124 | chan_frac = ((freq % 75) * 0x20000) / 75; |
| 122 | 125 | channelSel = (channelSel << 17) | chan_frac; |
| @@ -586,32 +589,19 @@ static void ar9003_hw_init_bb(struct ath_hw *ah, · 463 unmodified lines | ||
| 586 | 589 | ath9k_hw_synth_delay(ah, chan, synthDelay); |
| 587 | 590 | } |
| 588 | 591 | |
| 589 | −static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) | |
| 592 | +void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) | |
| 590 | 593 | { |
| 591 | − switch (rx) { | |
| 592 | − case 0x5: | |
| 594 | + if (ah->caps.tx_chainmask == 5 || ah->caps.rx_chainmask == 5) | |
| 593 | 595 | REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, |
| 594 | 596 | AR_PHY_SWAP_ALT_CHAIN); |
| 595 | − case 0x3: | |
| 596 | − case 0x1: | |
| 597 | − case 0x2: | |
| 598 | − case 0x7: | |
| 599 | − REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx); | |
| 600 | − REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx); | |
| 601 | − break; | |
| 602 | − default: | |
| 603 | − break; | |
| 604 | − } | |
| 597 | + | |
| 598 | + REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx); | |
| 599 | + REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx); | |
| 605 | 600 | |
| 606 | 601 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7)) |
| 607 | − REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); | |
| 608 | − else | |
| 609 | − REG_WRITE(ah, AR_SELFGEN_MASK, tx); | |
| 602 | + tx = 3; | |
| 610 | 603 | |
| 611 | − if (tx == 0x5) { | |
| 612 | − REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, | |
| 613 | − AR_PHY_SWAP_ALT_CHAIN); | |
| 614 | − } | |
| 604 | + REG_WRITE(ah, AR_SELFGEN_MASK, tx); | |
| 615 | 605 | } |
| 616 | 606 | |
| 617 | 607 | /* |
| @@ -1450,6 +1440,67 @@ set_rfmode: · 832 unmodified lines | ||
| 1450 | 1440 | return 0; |
| 1451 | 1441 | } |
| 1452 | 1442 | |
| 1443 | +static void ar9003_hw_spectral_scan_config(struct ath_hw *ah, | |
| 1444 | + struct ath_spec_scan *param) | |
| 1445 | +{ | |
| 1446 | + u8 count; | |
| 1447 | + | |
| 1448 | + if (!param->enabled) { | |
| 1449 | + REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, | |
| 1450 | + AR_PHY_SPECTRAL_SCAN_ENABLE); | |
| 1451 | + return; | |
| 1452 | + } | |
| 1453 | + | |
| 1454 | + REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA); | |
| 1455 | + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); | |
| 1456 | + | |
| 1457 | + /* on AR93xx and newer, count = 0 will make the the chip send | |
| 1458 | + * spectral samples endlessly. Check if this really was intended, | |
| 1459 | + * and fix otherwise. | |
| 1460 | + */ | |
| 1461 | + count = param->count; | |
| 1462 | + if (param->endless) | |
| 1463 | + count = 0; | |
| 1464 | + else if (param->count == 0) | |
| 1465 | + count = 1; | |
| 1466 | + | |
| 1467 | + if (param->short_repeat) | |
| 1468 | + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, | |
| 1469 | + AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); | |
| 1470 | + else | |
| 1471 | + REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, | |
| 1472 | + AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); | |
| 1473 | + | |
| 1474 | + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, | |
| 1475 | + AR_PHY_SPECTRAL_SCAN_COUNT, count); | |
| 1476 | + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, | |
| 1477 | + AR_PHY_SPECTRAL_SCAN_PERIOD, param->period); | |
| 1478 | + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, | |
| 1479 | + AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period); | |
| 1480 | + | |
| 1481 | + return; | |
| 1482 | +} | |
| 1483 | + | |
| 1484 | +static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah) | |
| 1485 | +{ | |
| 1486 | + /* Activate spectral scan */ | |
| 1487 | + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, | |
| 1488 | + AR_PHY_SPECTRAL_SCAN_ACTIVE); | |
| 1489 | +} | |
| 1490 | + | |
| 1491 | +static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah) | |
| 1492 | +{ | |
| 1493 | + struct ath_common *common = ath9k_hw_common(ah); | |
| 1494 | + | |
| 1495 | + /* Poll for spectral scan complete */ | |
| 1496 | + if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN, | |
| 1497 | + AR_PHY_SPECTRAL_SCAN_ACTIVE, | |
| 1498 | + 0, AH_WAIT_TIMEOUT)) { | |
| 1499 | + ath_err(common, "spectral scan wait failed\n"); | |
| 1500 | + return; | |
| 1501 | + } | |
| 1502 | +} | |
| 1503 | + | |
| 1453 | 1504 | void ar9003_hw_attach_phy_ops(struct ath_hw *ah) |
| 1454 | 1505 | { |
| 1455 | 1506 | struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); |
| @@ -1483,6 +1534,9 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) · 27 unmodified lines | ||
| 1483 | 1534 | ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; |
| 1484 | 1535 | ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; |
| 1485 | 1536 | ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv; |
| 1537 | + ops->spectral_scan_config = ar9003_hw_spectral_scan_config; | |
| 1538 | + ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger; | |
| 1539 | + ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait; | |
| 1486 | 1540 | |
| 1487 | 1541 | ar9003_hw_set_nf_limits(ah); |
| 1488 | 1542 | ar9003_hw_set_radar_conf(ah); |
| @@ -1028,7 +1028,7 @@ · 1027 unmodified lines | ||
| 1028 | 1028 | #define AR_PHY_TPC_5_B2 (AR_SM2_BASE + 0x208) |
| 1029 | 1029 | #define AR_PHY_TPC_6_B2 (AR_SM2_BASE + 0x20c) |
| 1030 | 1030 | #define AR_PHY_TPC_11_B2 (AR_SM2_BASE + 0x220) |
| 1031 | −#define AR_PHY_PDADC_TAB_2 (AR_SM2_BASE + 0x240) | |
| 1031 | +#define AR_PHY_TPC_19_B2 (AR_SM2_BASE + 0x240) | |
| 1032 | 1032 | #define AR_PHY_TX_IQCAL_STATUS_B2 (AR_SM2_BASE + 0x48c) |
| 1033 | 1033 | #define AR_PHY_TX_IQCAL_CORR_COEFF_B2(_i) (AR_SM2_BASE + 0x450 + ((_i) << 2)) |
| 1034 | 1034 | |
| @@ -1172,6 +1172,106 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = { · 1171 unmodified lines | ||
| 1172 | 1172 | {0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266}, |
| 1173 | 1173 | }; |
| 1174 | 1174 | |
| 1175 | +static const u32 ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0[][5] = { | |
| 1176 | + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | |
| 1177 | + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a}, | |
| 1178 | + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac}, | |
| 1179 | + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00}, | |
| 1180 | + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000}, | |
| 1181 | + {0x0000a394, 0x00000444, 0x00000444, 0x00000404, 0x00000404}, | |
| 1182 | + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, | |
| 1183 | + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 1184 | + {0x0000a504, 0x06000003, 0x06000003, 0x02000001, 0x02000001}, | |
| 1185 | + {0x0000a508, 0x0a000020, 0x0a000020, 0x05000003, 0x05000003}, | |
| 1186 | + {0x0000a50c, 0x10000023, 0x10000023, 0x0a000005, 0x0a000005}, | |
| 1187 | + {0x0000a510, 0x16000220, 0x16000220, 0x0e000201, 0x0e000201}, | |
| 1188 | + {0x0000a514, 0x1c000223, 0x1c000223, 0x11000203, 0x11000203}, | |
| 1189 | + {0x0000a518, 0x21002220, 0x21002220, 0x14000401, 0x14000401}, | |
| 1190 | + {0x0000a51c, 0x27002223, 0x27002223, 0x18000403, 0x18000403}, | |
| 1191 | + {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000602, 0x1b000602}, | |
| 1192 | + {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000802, 0x1f000802}, | |
| 1193 | + {0x0000a528, 0x34022225, 0x34022225, 0x21000620, 0x21000620}, | |
| 1194 | + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x25000820, 0x25000820}, | |
| 1195 | + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x29000822, 0x29000822}, | |
| 1196 | + {0x0000a534, 0x4202242a, 0x4202242a, 0x2d000824, 0x2d000824}, | |
| 1197 | + {0x0000a538, 0x4702244a, 0x4702244a, 0x30000828, 0x30000828}, | |
| 1198 | + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x3400082a, 0x3400082a}, | |
| 1199 | + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38000849, 0x38000849}, | |
| 1200 | + {0x0000a544, 0x5302266c, 0x5302266c, 0x3b000a2c, 0x3b000a2c}, | |
| 1201 | + {0x0000a548, 0x5702286c, 0x5702286c, 0x3e000e2b, 0x3e000e2b}, | |
| 1202 | + {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42000e2d, 0x42000e2d}, | |
| 1203 | + {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4500124a, 0x4500124a}, | |
| 1204 | + {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4900124c, 0x4900124c}, | |
| 1205 | + {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c00126c, 0x4c00126c}, | |
| 1206 | + {0x0000a55c, 0x7002708c, 0x7002708c, 0x4f00128c, 0x4f00128c}, | |
| 1207 | + {0x0000a560, 0x7302b08a, 0x7302b08a, 0x52001290, 0x52001290}, | |
| 1208 | + {0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, | |
| 1209 | + {0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, | |
| 1210 | + {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, | |
| 1211 | + {0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, | |
| 1212 | + {0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, | |
| 1213 | + {0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, | |
| 1214 | + {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, | |
| 1215 | + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, | |
| 1216 | + {0x0000a584, 0x06800003, 0x06800003, 0x02800001, 0x02800001}, | |
| 1217 | + {0x0000a588, 0x0a800020, 0x0a800020, 0x05800003, 0x05800003}, | |
| 1218 | + {0x0000a58c, 0x10800023, 0x10800023, 0x0a800005, 0x0a800005}, | |
| 1219 | + {0x0000a590, 0x16800220, 0x16800220, 0x0e800201, 0x0e800201}, | |
| 1220 | + {0x0000a594, 0x1c800223, 0x1c800223, 0x11800203, 0x11800203}, | |
| 1221 | + {0x0000a598, 0x21820220, 0x21820220, 0x14800401, 0x14800401}, | |
| 1222 | + {0x0000a59c, 0x27820223, 0x27820223, 0x18800403, 0x18800403}, | |
| 1223 | + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800602, 0x1b800602}, | |
| 1224 | + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800802, 0x1f800802}, | |
| 1225 | + {0x0000a5a8, 0x34822225, 0x34822225, 0x21800620, 0x21800620}, | |
| 1226 | + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x25800820, 0x25800820}, | |
| 1227 | + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x29800822, 0x29800822}, | |
| 1228 | + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2d800824, 0x2d800824}, | |
| 1229 | + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x30800828, 0x30800828}, | |
| 1230 | + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x3480082a, 0x3480082a}, | |
| 1231 | + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38800849, 0x38800849}, | |
| 1232 | + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b800a2c, 0x3b800a2c}, | |
| 1233 | + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e800e2b, 0x3e800e2b}, | |
| 1234 | + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42800e2d, 0x42800e2d}, | |
| 1235 | + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4580124a, 0x4580124a}, | |
| 1236 | + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4980124c, 0x4980124c}, | |
| 1237 | + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c80126c, 0x4c80126c}, | |
| 1238 | + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x4f80128c, 0x4f80128c}, | |
| 1239 | + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x52801290, 0x52801290}, | |
| 1240 | + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, | |
| 1241 | + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, | |
| 1242 | + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, | |
| 1243 | + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, | |
| 1244 | + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, | |
| 1245 | + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, | |
| 1246 | + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, | |
| 1247 | + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 1248 | + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 1249 | + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 1250 | + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 1251 | + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 1252 | + {0x0000a614, 0x01404000, 0x01404000, 0x01404501, 0x01404501}, | |
| 1253 | + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, | |
| 1254 | + {0x0000a61c, 0x02008802, 0x02008802, 0x01404501, 0x01404501}, | |
| 1255 | + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x03c0cf02, 0x03c0cf02}, | |
| 1256 | + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03c0cf03, 0x03c0cf03}, | |
| 1257 | + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04011004, 0x04011004}, | |
| 1258 | + {0x0000a62c, 0x03810c03, 0x03810c03, 0x05419405, 0x05419405}, | |
| 1259 | + {0x0000a630, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506}, | |
| 1260 | + {0x0000a634, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506}, | |
| 1261 | + {0x0000a638, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506}, | |
| 1262 | + {0x0000a63c, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506}, | |
| 1263 | + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a}, | |
| 1264 | + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac}, | |
| 1265 | + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00}, | |
| 1266 | + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000}, | |
| 1267 | + {0x00016044, 0x022492db, 0x022492db, 0x022492db, 0x022492db}, | |
| 1268 | + {0x00016048, 0x24925666, 0x24925666, 0x24925266, 0x24925266}, | |
| 1269 | + {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015}, | |
| 1270 | + {0x00016288, 0xf0318000, 0xf0318000, 0xf0318000, 0xf0318000}, | |
| 1271 | + {0x00016444, 0x022492db, 0x022492db, 0x022492db, 0x022492db}, | |
| 1272 | + {0x00016448, 0x24925666, 0x24925666, 0x24925266, 0x24925266}, | |
| 1273 | +}; | |
| 1274 | + | |
| 1175 | 1275 | static const u32 ar9340_1p0_mac_core[][2] = { |
| 1176 | 1276 | /* Addr allmodes */ |
| 1177 | 1277 | {0x00000008, 0x00000000}, |
| @@ -260,6 +260,79 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { · 259 unmodified lines | ||
| 260 | 260 | {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, |
| 261 | 261 | }; |
| 262 | 262 | |
| 263 | +static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = { | |
| 264 | + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | |
| 265 | + {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, | |
| 266 | + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, | |
| 267 | + {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, | |
| 268 | + {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006}, | |
| 269 | + {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201}, | |
| 270 | + {0x0000a508, 0x0c002e00, 0x0c002e00, 0x06000203, 0x06000203}, | |
| 271 | + {0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401}, | |
| 272 | + {0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403}, | |
| 273 | + {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405}, | |
| 274 | + {0x0000a518, 0x25020ec0, 0x25020ec0, 0x15000604, 0x15000604}, | |
| 275 | + {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x18000605, 0x18000605}, | |
| 276 | + {0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000a04, 0x1c000a04}, | |
| 277 | + {0x0000a524, 0x35001fc4, 0x35001fc4, 0x21000a06, 0x21000a06}, | |
| 278 | + {0x0000a528, 0x3c022f04, 0x3c022f04, 0x29000a24, 0x29000a24}, | |
| 279 | + {0x0000a52c, 0x41023e85, 0x41023e85, 0x2f000e21, 0x2f000e21}, | |
| 280 | + {0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000e20, 0x31000e20}, | |
| 281 | + {0x0000a534, 0x4d023f01, 0x4d023f01, 0x33000e20, 0x33000e20}, | |
| 282 | + {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, | |
| 283 | + {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, | |
| 284 | + {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, | |
| 285 | + {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, | |
| 286 | + {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, | |
| 287 | + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, | |
| 288 | + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, | |
| 289 | + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, | |
| 290 | + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, | |
| 291 | + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, | |
| 292 | + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, | |
| 293 | + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, | |
| 294 | + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, | |
| 295 | + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, | |
| 296 | + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, | |
| 297 | + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, | |
| 298 | + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, | |
| 299 | + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, | |
| 300 | + {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 301 | + {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 302 | + {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 303 | + {0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 304 | + {0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 305 | + {0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 306 | + {0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 307 | + {0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 308 | + {0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 309 | + {0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 310 | + {0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 311 | + {0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a}, | |
| 312 | + {0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a}, | |
| 313 | + {0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a}, | |
| 314 | + {0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 315 | + {0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 316 | + {0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 317 | + {0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 318 | + {0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 319 | + {0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 320 | + {0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 321 | + {0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 322 | + {0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 323 | + {0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 324 | + {0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 325 | + {0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 326 | + {0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 327 | + {0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 328 | + {0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 329 | + {0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 330 | + {0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 331 | + {0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 332 | + {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, | |
| 333 | + {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, | |
| 334 | +}; | |
| 335 | + | |
| 263 | 336 | static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = { |
| 264 | 337 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ |
| 265 | 338 | {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, |
| @@ -450,6 +523,79 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = { · 184 unmodified lines | ||
| 450 | 523 | |
| 451 | 524 | #define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1 |
| 452 | 525 | |
| 526 | +static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = { | |
| 527 | + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | |
| 528 | + {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, | |
| 529 | + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, | |
| 530 | + {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, | |
| 531 | + {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006}, | |
| 532 | + {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201}, | |
| 533 | + {0x0000a508, 0x0c002e00, 0x0c002e00, 0x07000203, 0x07000203}, | |
| 534 | + {0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401}, | |
| 535 | + {0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403}, | |
| 536 | + {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405}, | |
| 537 | + {0x0000a518, 0x25020ec0, 0x25020ec0, 0x14000406, 0x14000406}, | |
| 538 | + {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1800040a, 0x1800040a}, | |
| 539 | + {0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000460, 0x1c000460}, | |
| 540 | + {0x0000a524, 0x35001fc4, 0x35001fc4, 0x22000463, 0x22000463}, | |
| 541 | + {0x0000a528, 0x3c022f04, 0x3c022f04, 0x26000465, 0x26000465}, | |
| 542 | + {0x0000a52c, 0x41023e85, 0x41023e85, 0x2e0006e0, 0x2e0006e0}, | |
| 543 | + {0x0000a530, 0x48023ec6, 0x48023ec6, 0x310006e0, 0x310006e0}, | |
| 544 | + {0x0000a534, 0x4d023f01, 0x4d023f01, 0x330006e0, 0x330006e0}, | |
| 545 | + {0x0000a538, 0x53023f4b, 0x53023f4b, 0x3e0008e3, 0x3e0008e3}, | |
| 546 | + {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x410008e5, 0x410008e5}, | |
| 547 | + {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x430008e6, 0x430008e6}, | |
| 548 | + {0x0000a544, 0x6502feca, 0x6502feca, 0x4a0008ec, 0x4a0008ec}, | |
| 549 | + {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4e0008f1, 0x4e0008f1}, | |
| 550 | + {0x0000a54c, 0x7203feca, 0x7203feca, 0x520008f3, 0x520008f3}, | |
| 551 | + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x54000eed, 0x54000eed}, | |
| 552 | + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x58000ef1, 0x58000ef1}, | |
| 553 | + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5c000ef3, 0x5c000ef3}, | |
| 554 | + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x60000ef5, 0x60000ef5}, | |
| 555 | + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x62000ef6, 0x62000ef6}, | |
| 556 | + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x62000ef6, 0x62000ef6}, | |
| 557 | + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, | |
| 558 | + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, | |
| 559 | + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, | |
| 560 | + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, | |
| 561 | + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, | |
| 562 | + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, | |
| 563 | + {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 564 | + {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 565 | + {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 566 | + {0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 567 | + {0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 568 | + {0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 569 | + {0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 570 | + {0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 571 | + {0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 572 | + {0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 573 | + {0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, | |
| 574 | + {0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a}, | |
| 575 | + {0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a}, | |
| 576 | + {0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a}, | |
| 577 | + {0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 578 | + {0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 579 | + {0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 580 | + {0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 581 | + {0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 582 | + {0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 583 | + {0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 584 | + {0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 585 | + {0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 586 | + {0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 587 | + {0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 588 | + {0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 589 | + {0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 590 | + {0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 591 | + {0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 592 | + {0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 593 | + {0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 594 | + {0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, | |
| 595 | + {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, | |
| 596 | + {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, | |
| 597 | +}; | |
| 598 | + | |
| 453 | 599 | static const u32 ar9485_1_1[][2] = { |
| 454 | 600 | /* Addr allmodes */ |
| 455 | 601 | {0x0000a580, 0x00000000}, |
| @@ -23,16 +23,16 @@ · 22 unmodified lines | ||
| 23 | 23 | static const u32 ar955x_1p0_radio_postamble[][5] = { |
| 24 | 24 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ |
| 25 | 25 | {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330}, |
| 26 | − {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x06345f2a, 0x06345f2a}, | |
| 27 | − {0x000160ac, 0xa4647c00, 0xa4647c00, 0xa4646800, 0xa4646800}, | |
| 28 | − {0x000160b0, 0x01885f52, 0x01885f52, 0x04accf3a, 0x04accf3a}, | |
| 29 | − {0x00016104, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, | |
| 26 | + {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a}, | |
| 27 | + {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24647c00, 0x24647c00}, | |
| 28 | + {0x000160b0, 0x01885f52, 0x01885f52, 0x01885f52, 0x01885f52}, | |
| 29 | + {0x00016104, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001}, | |
| 30 | 30 | {0x0001610c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, |
| 31 | 31 | {0x00016140, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, |
| 32 | − {0x00016504, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, | |
| 32 | + {0x00016504, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001}, | |
| 33 | 33 | {0x0001650c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, |
| 34 | 34 | {0x00016540, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, |
| 35 | − {0x00016904, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, | |
| 35 | + {0x00016904, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001}, | |
| 36 | 36 | {0x0001690c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, |
| 37 | 37 | {0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, |
| 38 | 38 | }; |
| @@ -69,15 +69,15 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = { · 30 unmodified lines | ||
| 69 | 69 | {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0}, |
| 70 | 70 | {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, |
| 71 | 71 | {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, |
| 72 | − {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, | |
| 72 | + {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, | |
| 73 | 73 | {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, |
| 74 | 74 | {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, |
| 75 | 75 | {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, |
| 76 | 76 | {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, |
| 77 | 77 | {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, |
| 78 | − {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, | |
| 78 | + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, | |
| 79 | 79 | {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, |
| 80 | − {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, | |
| 80 | + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, | |
| 81 | 81 | {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, |
| 82 | 82 | {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, |
| 83 | 83 | {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, |
| @@ -125,7 +125,7 @@ static const u32 ar955x_1p0_radio_core[][2] = { · 41 unmodified lines | ||
| 125 | 125 | {0x00016094, 0x00000000}, |
| 126 | 126 | {0x000160a0, 0x0a108ffe}, |
| 127 | 127 | {0x000160a4, 0x812fc370}, |
| 128 | − {0x000160a8, 0x423c8000}, | |
| 128 | + {0x000160a8, 0x423c8100}, | |
| 129 | 129 | {0x000160b4, 0x92480080}, |
| 130 | 130 | {0x000160c0, 0x006db6d0}, |
| 131 | 131 | {0x000160c4, 0x6db6db60}, |
| @@ -134,7 +134,7 @@ static const u32 ar955x_1p0_radio_core[][2] = { · 2 unmodified lines | ||
| 134 | 134 | {0x00016100, 0x11999601}, |
| 135 | 135 | {0x00016108, 0x00080010}, |
| 136 | 136 | {0x00016144, 0x02084080}, |
| 137 | − {0x00016148, 0x000080c0}, | |
| 137 | + {0x00016148, 0x00008040}, | |
| 138 | 138 | {0x00016280, 0x01800804}, |
| 139 | 139 | {0x00016284, 0x00038dc5}, |
| 140 | 140 | {0x00016288, 0x00000000}, |
| @@ -178,7 +178,7 @@ static const u32 ar955x_1p0_radio_core[][2] = { · 37 unmodified lines | ||
| 178 | 178 | {0x00016500, 0x11999601}, |
| 179 | 179 | {0x00016508, 0x00080010}, |
| 180 | 180 | {0x00016544, 0x02084080}, |
| 181 | − {0x00016548, 0x000080c0}, | |
| 181 | + {0x00016548, 0x00008040}, | |
| 182 | 182 | {0x00016780, 0x00000000}, |
| 183 | 183 | {0x00016784, 0x00000000}, |
| 184 | 184 | {0x00016788, 0x00400705}, |
| @@ -218,7 +218,7 @@ static const u32 ar955x_1p0_radio_core[][2] = { · 33 unmodified lines | ||
| 218 | 218 | {0x00016900, 0x11999601}, |
| 219 | 219 | {0x00016908, 0x00080010}, |
| 220 | 220 | {0x00016944, 0x02084080}, |
| 221 | − {0x00016948, 0x000080c0}, | |
| 221 | + {0x00016948, 0x00008040}, | |
| 222 | 222 | {0x00016b80, 0x00000000}, |
| 223 | 223 | {0x00016b84, 0x00000000}, |
| 224 | 224 | {0x00016b88, 0x00400705}, |
| @@ -245,9 +245,9 @@ static const u32 ar955x_1p0_radio_core[][2] = { · 20 unmodified lines | ||
| 245 | 245 | |
| 246 | 246 | static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = { |
| 247 | 247 | /* Addr 5G_HT20_L 5G_HT40_L 5G_HT20_M 5G_HT40_M 5G_HT20_H 5G_HT40_H 2G_HT40 2G_HT20 */ |
| 248 | − {0x0000a2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, | |
| 249 | − {0x0000a2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, | |
| 250 | − {0x0000a2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, | |
| 248 | + {0x0000a2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa}, | |
| 249 | + {0x0000a2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc}, | |
| 250 | + {0x0000a2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0}, | |
| 251 | 251 | {0x0000a2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, |
| 252 | 252 | {0x0000a410, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050da, 0x000050da}, |
| 253 | 253 | {0x0000a500, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000000, 0x00000000}, |
| @@ -256,63 +256,63 @@ static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = { · 2 unmodified lines | ||
| 256 | 256 | {0x0000a50c, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c000006, 0x0c000006}, |
| 257 | 257 | {0x0000a510, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x0f00000a, 0x0f00000a}, |
| 258 | 258 | {0x0000a514, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x1300000c, 0x1300000c}, |
| 259 | − {0x0000a518, 0x19004008, 0x19004008, 0x19004008, 0x19004008, 0x18004008, 0x18004008, 0x1700000e, 0x1700000e}, | |
| 260 | − {0x0000a51c, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1c00400a, 0x1c00400a, 0x1b000064, 0x1b000064}, | |
| 261 | − {0x0000a520, 0x230020a2, 0x230020a2, 0x210020a2, 0x210020a2, 0x200020a2, 0x200020a2, 0x1f000242, 0x1f000242}, | |
| 262 | − {0x0000a524, 0x2500006e, 0x2500006e, 0x2500006e, 0x2500006e, 0x2400006e, 0x2400006e, 0x23000229, 0x23000229}, | |
| 263 | − {0x0000a528, 0x29022221, 0x29022221, 0x28022221, 0x28022221, 0x27022221, 0x27022221, 0x270002a2, 0x270002a2}, | |
| 264 | − {0x0000a52c, 0x2d00062a, 0x2d00062a, 0x2c00062a, 0x2c00062a, 0x2a00062a, 0x2a00062a, 0x2c001203, 0x2c001203}, | |
| 265 | − {0x0000a530, 0x340220a5, 0x340220a5, 0x320220a5, 0x320220a5, 0x2f0220a5, 0x2f0220a5, 0x30001803, 0x30001803}, | |
| 266 | − {0x0000a534, 0x380022c5, 0x380022c5, 0x350022c5, 0x350022c5, 0x320022c5, 0x320022c5, 0x33000881, 0x33000881}, | |
| 267 | − {0x0000a538, 0x3b002486, 0x3b002486, 0x39002486, 0x39002486, 0x36002486, 0x36002486, 0x38001809, 0x38001809}, | |
| 268 | − {0x0000a53c, 0x3f00248a, 0x3f00248a, 0x3d00248a, 0x3d00248a, 0x3a00248a, 0x3a00248a, 0x3a000814, 0x3a000814}, | |
| 269 | − {0x0000a540, 0x4202242c, 0x4202242c, 0x4102242c, 0x4102242c, 0x3f02242c, 0x3f02242c, 0x3f001a0c, 0x3f001a0c}, | |
| 270 | − {0x0000a544, 0x490044c6, 0x490044c6, 0x460044c6, 0x460044c6, 0x420044c6, 0x420044c6, 0x43001a0e, 0x43001a0e}, | |
| 271 | − {0x0000a548, 0x4d024485, 0x4d024485, 0x4a024485, 0x4a024485, 0x46024485, 0x46024485, 0x46001812, 0x46001812}, | |
| 272 | − {0x0000a54c, 0x51044483, 0x51044483, 0x4e044483, 0x4e044483, 0x4a044483, 0x4a044483, 0x49001884, 0x49001884}, | |
| 273 | − {0x0000a550, 0x5404a40c, 0x5404a40c, 0x5204a40c, 0x5204a40c, 0x4d04a40c, 0x4d04a40c, 0x4d001e84, 0x4d001e84}, | |
| 274 | − {0x0000a554, 0x57024632, 0x57024632, 0x55024632, 0x55024632, 0x52024632, 0x52024632, 0x50001e69, 0x50001e69}, | |
| 275 | − {0x0000a558, 0x5c00a634, 0x5c00a634, 0x5900a634, 0x5900a634, 0x5600a634, 0x5600a634, 0x550006f4, 0x550006f4}, | |
| 276 | − {0x0000a55c, 0x5f026832, 0x5f026832, 0x5d026832, 0x5d026832, 0x5a026832, 0x5a026832, 0x59000ad3, 0x59000ad3}, | |
| 277 | − {0x0000a560, 0x6602b012, 0x6602b012, 0x6202b012, 0x6202b012, 0x5d02b012, 0x5d02b012, 0x5e000ad5, 0x5e000ad5}, | |
| 278 | − {0x0000a564, 0x6e02d0e1, 0x6e02d0e1, 0x6802d0e1, 0x6802d0e1, 0x6002d0e1, 0x6002d0e1, 0x61001ced, 0x61001ced}, | |
| 279 | − {0x0000a568, 0x7202b4c4, 0x7202b4c4, 0x6c02b4c4, 0x6c02b4c4, 0x6502b4c4, 0x6502b4c4, 0x660018d4, 0x660018d4}, | |
| 280 | − {0x0000a56c, 0x75007894, 0x75007894, 0x70007894, 0x70007894, 0x6b007894, 0x6b007894, 0x660018d4, 0x660018d4}, | |
| 281 | − {0x0000a570, 0x7b025c74, 0x7b025c74, 0x75025c74, 0x75025c74, 0x70025c74, 0x70025c74, 0x660018d4, 0x660018d4}, | |
| 282 | − {0x0000a574, 0x8300bcb5, 0x8300bcb5, 0x7a00bcb5, 0x7a00bcb5, 0x7600bcb5, 0x7600bcb5, 0x660018d4, 0x660018d4}, | |
| 283 | − {0x0000a578, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4}, | |
| 284 | − {0x0000a57c, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4}, | |
| 259 | + {0x0000a518, 0x1700002b, 0x1700002b, 0x1700002b, 0x1700002b, 0x1600002b, 0x1600002b, 0x1700000e, 0x1700000e}, | |
| 260 | + {0x0000a51c, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1a00002d, 0x1a00002d, 0x1b000064, 0x1b000064}, | |
| 261 | + {0x0000a520, 0x20000031, 0x20000031, 0x1f000031, 0x1f000031, 0x1e000031, 0x1e000031, 0x1f000242, 0x1f000242}, | |
| 262 | + {0x0000a524, 0x24000051, 0x24000051, 0x23000051, 0x23000051, 0x23000051, 0x23000051, 0x23000229, 0x23000229}, | |
| 263 | + {0x0000a528, 0x27000071, 0x27000071, 0x27000071, 0x27000071, 0x26000071, 0x26000071, 0x270002a2, 0x270002a2}, | |
| 264 | + {0x0000a52c, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2c001203, 0x2c001203}, | |
| 265 | + {0x0000a530, 0x3000028c, 0x3000028c, 0x2f00028c, 0x2f00028c, 0x2e00028c, 0x2e00028c, 0x30001803, 0x30001803}, | |
| 266 | + {0x0000a534, 0x34000290, 0x34000290, 0x33000290, 0x33000290, 0x32000290, 0x32000290, 0x33000881, 0x33000881}, | |
| 267 | + {0x0000a538, 0x37000292, 0x37000292, 0x36000292, 0x36000292, 0x35000292, 0x35000292, 0x38001809, 0x38001809}, | |
| 268 | + {0x0000a53c, 0x3b02028d, 0x3b02028d, 0x3a02028d, 0x3a02028d, 0x3902028d, 0x3902028d, 0x3a000814, 0x3a000814}, | |
| 269 | + {0x0000a540, 0x3f020291, 0x3f020291, 0x3e020291, 0x3e020291, 0x3d020291, 0x3d020291, 0x3f001a0c, 0x3f001a0c}, | |
| 270 | + {0x0000a544, 0x44020490, 0x44020490, 0x43020490, 0x43020490, 0x42020490, 0x42020490, 0x43001a0e, 0x43001a0e}, | |
| 271 | + {0x0000a548, 0x48020492, 0x48020492, 0x47020492, 0x47020492, 0x46020492, 0x46020492, 0x46001812, 0x46001812}, | |
| 272 | + {0x0000a54c, 0x4c020692, 0x4c020692, 0x4b020692, 0x4b020692, 0x4a020692, 0x4a020692, 0x49001884, 0x49001884}, | |
| 273 | + {0x0000a550, 0x50020892, 0x50020892, 0x4f020892, 0x4f020892, 0x4e020892, 0x4e020892, 0x4d001e84, 0x4d001e84}, | |
| 274 | + {0x0000a554, 0x53040891, 0x53040891, 0x53040891, 0x53040891, 0x52040891, 0x52040891, 0x50001e69, 0x50001e69}, | |
| 275 | + {0x0000a558, 0x58040893, 0x58040893, 0x57040893, 0x57040893, 0x56040893, 0x56040893, 0x550006f4, 0x550006f4}, | |
| 276 | + {0x0000a55c, 0x5c0408b4, 0x5c0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x59000ad3, 0x59000ad3}, | |
| 277 | + {0x0000a560, 0x610408b6, 0x610408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e000ad5, 0x5e000ad5}, | |
| 278 | + {0x0000a564, 0x670408f6, 0x670408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x61001ced, 0x61001ced}, | |
| 279 | + {0x0000a568, 0x6a040cf6, 0x6a040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x660018d4, 0x660018d4}, | |
| 280 | + {0x0000a56c, 0x6d040d76, 0x6d040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x660018d4, 0x660018d4}, | |
| 281 | + {0x0000a570, 0x70060db6, 0x70060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x660018d4, 0x660018d4}, | |
| 282 | + {0x0000a574, 0x730a0df6, 0x730a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x660018d4, 0x660018d4}, | |
| 283 | + {0x0000a578, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4}, | |
| 284 | + {0x0000a57c, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4}, | |
| 285 | 285 | {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
| 286 | 286 | {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
| 287 | 287 | {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
| 288 | − {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x03804000, 0x03804000}, | |
| 289 | − {0x0000a610, 0x04c08c01, 0x04c08c01, 0x04808b01, 0x04808b01, 0x04808a01, 0x04808a01, 0x0300ca02, 0x0300ca02}, | |
| 290 | − {0x0000a614, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00000e04, 0x00000e04}, | |
| 291 | − {0x0000a618, 0x04010c01, 0x04010c01, 0x03c10b01, 0x03c10b01, 0x03810a01, 0x03810a01, 0x03014000, 0x03014000}, | |
| 292 | − {0x0000a61c, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x00000000, 0x00000000}, | |
| 293 | − {0x0000a620, 0x04010303, 0x04010303, 0x03c10303, 0x03c10303, 0x03810303, 0x03810303, 0x00000000, 0x00000000}, | |
| 294 | − {0x0000a624, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03014000, 0x03014000}, | |
| 295 | − {0x0000a628, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x03804c05, 0x03804c05}, | |
| 296 | − {0x0000a62c, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x0701de06, 0x0701de06}, | |
| 297 | − {0x0000a630, 0x03418000, 0x03418000, 0x03018000, 0x03018000, 0x02c18000, 0x02c18000, 0x07819c07, 0x07819c07}, | |
| 298 | − {0x0000a634, 0x03815004, 0x03815004, 0x03414f04, 0x03414f04, 0x03414e04, 0x03414e04, 0x0701dc07, 0x0701dc07}, | |
| 299 | − {0x0000a638, 0x03005302, 0x03005302, 0x02c05202, 0x02c05202, 0x02805202, 0x02805202, 0x0701dc07, 0x0701dc07}, | |
| 300 | − {0x0000a63c, 0x04c09302, 0x04c09302, 0x04809202, 0x04809202, 0x04809202, 0x04809202, 0x0701dc07, 0x0701dc07}, | |
| 301 | − {0x0000b2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, | |
| 302 | − {0x0000b2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, | |
| 303 | − {0x0000b2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, | |
| 288 | + {0x0000a60c, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x03804000, 0x03804000}, | |
| 289 | + {0x0000a610, 0x04008b01, 0x04008b01, 0x04008b01, 0x04008b01, 0x03c08b01, 0x03c08b01, 0x0300ca02, 0x0300ca02}, | |
| 290 | + {0x0000a614, 0x05811403, 0x05811403, 0x05411303, 0x05411303, 0x05411303, 0x05411303, 0x00000e04, 0x00000e04}, | |
| 291 | + {0x0000a618, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000}, | |
| 292 | + {0x0000a61c, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000}, | |
| 293 | + {0x0000a620, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000}, | |
| 294 | + {0x0000a624, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000}, | |
| 295 | + {0x0000a628, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03804c05, 0x03804c05}, | |
| 296 | + {0x0000a62c, 0x06815604, 0x06815604, 0x06415504, 0x06415504, 0x06015504, 0x06015504, 0x0701de06, 0x0701de06}, | |
| 297 | + {0x0000a630, 0x07819a05, 0x07819a05, 0x07419905, 0x07419905, 0x07019805, 0x07019805, 0x07819c07, 0x07819c07}, | |
| 298 | + {0x0000a634, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07}, | |
| 299 | + {0x0000a638, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07}, | |
| 300 | + {0x0000a63c, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07}, | |
| 301 | + {0x0000b2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa}, | |
| 302 | + {0x0000b2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc}, | |
| 303 | + {0x0000b2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0}, | |
| 304 | 304 | {0x0000b2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, |
| 305 | − {0x0000c2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, | |
| 306 | − {0x0000c2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, | |
| 307 | − {0x0000c2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, | |
| 305 | + {0x0000c2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa}, | |
| 306 | + {0x0000c2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc}, | |
| 307 | + {0x0000c2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0}, | |
| 308 | 308 | {0x0000c2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, |
| 309 | 309 | {0x00016044, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, |
| 310 | − {0x00016048, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, | |
| 310 | + {0x00016048, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, | |
| 311 | 311 | {0x00016280, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01808e84, 0x01808e84}, |
| 312 | 312 | {0x00016444, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, |
| 313 | − {0x00016448, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, | |
| 313 | + {0x00016448, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, | |
| 314 | 314 | {0x00016844, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, |
| 315 | − {0x00016848, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, | |
| 315 | + {0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, | |
| 316 | 316 | }; |
| 317 | 317 | |
| 318 | 318 | static const u32 ar955x_1p0_mac_core[][2] = { |
| @@ -846,7 +846,7 @@ static const u32 ar955x_1p0_baseband_core[][2] = { · 527 unmodified lines | ||
| 846 | 846 | {0x0000a44c, 0x00000001}, |
| 847 | 847 | {0x0000a450, 0x00010000}, |
| 848 | 848 | {0x0000a458, 0x00000000}, |
| 849 | − {0x0000a644, 0x3fad9d74}, | |
| 849 | + {0x0000a644, 0xbfad9d74}, | |
| 850 | 850 | {0x0000a648, 0x0048060a}, |
| 851 | 851 | {0x0000a64c, 0x00003c37}, |
| 852 | 852 | {0x0000a670, 0x03020100}, |
| @@ -1277,7 +1277,7 @@ static const u32 ar955x_1p0_modes_fast_clock[][3] = { · 424 unmodified lines | ||
| 1277 | 1277 | {0x0000801c, 0x148ec02b, 0x148ec057}, |
| 1278 | 1278 | {0x00008318, 0x000044c0, 0x00008980}, |
| 1279 | 1279 | {0x00009e00, 0x0372131c, 0x0372131c}, |
| 1280 | − {0x0000a230, 0x0000000b, 0x00000016}, | |
| 1280 | + {0x0000a230, 0x0000400b, 0x00004016}, | |
| 1281 | 1281 | {0x0000a254, 0x00000898, 0x00001130}, |
| 1282 | 1282 | }; |
| 1283 | 1283 | |
| @@ -685,6 +685,82 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = { · 684 unmodified lines | ||
| 685 | 685 | |
| 686 | 686 | #define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2 |
| 687 | 687 | |
| 688 | +#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2 | |
| 689 | + | |
| 690 | +static const u32 ar9580_1p0_type6_tx_gain_table[][5] = { | |
| 691 | + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | |
| 692 | + {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, | |
| 693 | + {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, | |
| 694 | + {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, | |
| 695 | + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | |
| 696 | + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, | |
| 697 | + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 698 | + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, | |
| 699 | + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, | |
| 700 | + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, | |
| 701 | + {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, | |
| 702 | + {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, | |
| 703 | + {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, | |
| 704 | + {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, | |
| 705 | + {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, | |
| 706 | + {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, | |
| 707 | + {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, | |
| 708 | + {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, | |
| 709 | + {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, | |
| 710 | + {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, | |
| 711 | + {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, | |
| 712 | + {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, | |
| 713 | + {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, | |
| 714 | + {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, | |
| 715 | + {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, | |
| 716 | + {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83}, | |
| 717 | + {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84}, | |
| 718 | + {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, | |
| 719 | + {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, | |
| 720 | + {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, | |
| 721 | + {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, | |
| 722 | + {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 723 | + {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 724 | + {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 725 | + {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 726 | + {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 727 | + {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 728 | + {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, | |
| 729 | + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 730 | + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | |
| 731 | + {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, | |
| 732 | + {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, | |
| 733 | + {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, | |
| 734 | + {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, | |
| 735 | + {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, | |
| 736 | + {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, | |
| 737 | + {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, | |
| 738 | + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, | |
| 739 | + {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, | |
| 740 | + {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, | |
| 741 | + {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, | |
| 742 | + {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, | |
| 743 | + {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, | |
| 744 | + {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, | |
| 745 | + {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, | |
| 746 | + {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, | |
| 747 | + {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, | |
| 748 | + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | |
| 749 | + {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, | |
| 750 | + {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, | |
| 751 | + {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, | |
| 752 | + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | |
| 753 | + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, | |
| 754 | + {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, | |
| 755 | + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, | |
| 756 | + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, | |
| 757 | + {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, | |
| 758 | + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, | |
| 759 | + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, | |
| 760 | + {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, | |
| 761 | + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, | |
| 762 | +}; | |
| 763 | + | |
| 688 | 764 | static const u32 ar9580_1p0_soc_preamble[][2] = { |
| 689 | 765 | /* Addr allmodes */ |
| 690 | 766 | {0x000040a4, 0x00a0c1c9}, |
| @@ -109,14 +109,11 @@ struct ath_descdma { · 108 unmodified lines | ||
| 109 | 109 | void *dd_desc; |
| 110 | 110 | dma_addr_t dd_desc_paddr; |
| 111 | 111 | u32 dd_desc_len; |
| 112 | − struct ath_buf *dd_bufptr; | |
| 113 | 112 | }; |
| 114 | 113 | |
| 115 | 114 | int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, |
| 116 | 115 | struct list_head *head, const char *name, |
| 117 | 116 | int nbuf, int ndesc, bool is_tx); |
| 118 | −void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, | |
| 119 | − struct list_head *head); | |
| 120 | 117 | |
| 121 | 118 | /***********/ |
| 122 | 119 | /* RX / TX */ |
| @@ -317,10 +314,8 @@ struct ath_rx { · 194 unmodified lines | ||
| 317 | 314 | u32 *rxlink; |
| 318 | 315 | u32 num_pkts; |
| 319 | 316 | unsigned int rxfilter; |
| 320 | − spinlock_t rxbuflock; | |
| 321 | 317 | struct list_head rxbuf; |
| 322 | 318 | struct ath_descdma rxdma; |
| 323 | − struct ath_buf *rx_bufptr; | |
| 324 | 319 | struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; |
| 325 | 320 | |
| 326 | 321 | struct sk_buff *frag; |
| @@ -328,7 +323,6 @@ struct ath_rx { · 1 unmodified line | ||
| 328 | 323 | |
| 329 | 324 | int ath_startrecv(struct ath_softc *sc); |
| 330 | 325 | bool ath_stoprecv(struct ath_softc *sc); |
| 331 | −void ath_flushrecv(struct ath_softc *sc); | |
| 332 | 326 | u32 ath_calcrxfilter(struct ath_softc *sc); |
| 333 | 327 | int ath_rx_init(struct ath_softc *sc, int nbufs); |
| 334 | 328 | void ath_rx_cleanup(struct ath_softc *sc); |
| @@ -338,14 +332,12 @@ void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq); · 3 unmodified lines | ||
| 338 | 332 | void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq); |
| 339 | 333 | void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq); |
| 340 | 334 | void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); |
| 341 | −bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx); | |
| 342 | −void ath_draintxq(struct ath_softc *sc, | |
| 343 | − struct ath_txq *txq, bool retry_tx); | |
| 335 | +bool ath_drain_all_txq(struct ath_softc *sc); | |
| 336 | +void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq); | |
| 344 | 337 | void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); |
| 345 | 338 | void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); |
| 346 | 339 | void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); |
| 347 | 340 | int ath_tx_init(struct ath_softc *sc, int nbufs); |
| 348 | −void ath_tx_cleanup(struct ath_softc *sc); | |
| 349 | 341 | int ath_txq_update(struct ath_softc *sc, int qnum, |
| 350 | 342 | struct ath9k_tx_queue_info *q); |
| 351 | 343 | void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop); |
| @@ -646,7 +638,6 @@ void ath_ant_comb_update(struct ath_softc *sc); · 294 unmodified lines | ||
| 646 | 638 | enum sc_op_flags { |
| 647 | 639 | SC_OP_INVALID, |
| 648 | 640 | SC_OP_BEACONS, |
| 649 | − SC_OP_RXFLUSH, | |
| 650 | 641 | SC_OP_ANI_RUN, |
| 651 | 642 | SC_OP_PRIM_STA_VIF, |
| 652 | 643 | SC_OP_HW_RESET, |
| @@ -675,6 +666,23 @@ struct ath9k_vif_iter_data { · 22 unmodified lines | ||
| 675 | 666 | int nadhocs; /* number of adhoc vifs */ |
| 676 | 667 | }; |
| 677 | 668 | |
| 669 | +/* enum spectral_mode: | |
| 670 | + * | |
| 671 | + * @SPECTRAL_DISABLED: spectral mode is disabled | |
| 672 | + * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with | |
| 673 | + * something else. | |
| 674 | + * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples | |
| 675 | + * is performed manually. | |
| 676 | + * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels | |
| 677 | + * during a channel scan. | |
| 678 | + */ | |
| 679 | +enum spectral_mode { | |
| 680 | + SPECTRAL_DISABLED = 0, | |
| 681 | + SPECTRAL_BACKGROUND, | |
| 682 | + SPECTRAL_MANUAL, | |
| 683 | + SPECTRAL_CHANSCAN, | |
| 684 | +}; | |
| 685 | + | |
| 678 | 686 | struct ath_softc { |
| 679 | 687 | struct ieee80211_hw *hw; |
| 680 | 688 | struct device *dev; |
| @@ -743,6 +751,10 @@ struct ath_softc { · 62 unmodified lines | ||
| 743 | 751 | u8 ant_tx, ant_rx; |
| 744 | 752 | struct dfs_pattern_detector *dfs_detector; |
| 745 | 753 | u32 wow_enabled; |
| 754 | + /* relay(fs) channel for spectral scan */ | |
| 755 | + struct rchan *rfs_chan_spec_scan; | |
| 756 | + enum spectral_mode spectral_mode; | |
| 757 | + int scanning; | |
| 746 | 758 | |
| 747 | 759 | #ifdef CONFIG_PM_SLEEP |
| 748 | 760 | atomic_t wow_got_bmiss_intr; |
| @@ -751,6 +763,133 @@ struct ath_softc { · 2 unmodified lines | ||
| 751 | 763 | #endif |
| 752 | 764 | }; |
| 753 | 765 | |
| 766 | +#define SPECTRAL_SCAN_BITMASK 0x10 | |
| 767 | +/* Radar info packet format, used for DFS and spectral formats. */ | |
| 768 | +struct ath_radar_info { | |
| 769 | + u8 pulse_length_pri; | |
| 770 | + u8 pulse_length_ext; | |
| 771 | + u8 pulse_bw_info; | |
| 772 | +} __packed; | |
| 773 | + | |
| 774 | +/* The HT20 spectral data has 4 bytes of additional information at it's end. | |
| 775 | + * | |
| 776 | + * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]} | |
| 777 | + * [7:0]: all bins max_magnitude[9:2] | |
| 778 | + * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]} | |
| 779 | + * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) | |
| 780 | + */ | |
| 781 | +struct ath_ht20_mag_info { | |
| 782 | + u8 all_bins[3]; | |
| 783 | + u8 max_exp; | |
| 784 | +} __packed; | |
| 785 | + | |
| 786 | +#define SPECTRAL_HT20_NUM_BINS 56 | |
| 787 | + | |
| 788 | +/* WARNING: don't actually use this struct! MAC may vary the amount of | |
| 789 | + * data by -1/+2. This struct is for reference only. | |
| 790 | + */ | |
| 791 | +struct ath_ht20_fft_packet { | |
| 792 | + u8 data[SPECTRAL_HT20_NUM_BINS]; | |
| 793 | + struct ath_ht20_mag_info mag_info; | |
| 794 | + struct ath_radar_info radar_info; | |
| 795 | +} __packed; | |
| 796 | + | |
| 797 | +#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet)) | |
| 798 | + | |
| 799 | +/* Dynamic 20/40 mode: | |
| 800 | + * | |
| 801 | + * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]} | |
| 802 | + * [7:0]: lower bins max_magnitude[9:2] | |
| 803 | + * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]} | |
| 804 | + * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]} | |
| 805 | + * [7:0]: upper bins max_magnitude[9:2] | |
| 806 | + * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]} | |
| 807 | + * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) | |
| 808 | + */ | |
| 809 | +struct ath_ht20_40_mag_info { | |
| 810 | + u8 lower_bins[3]; | |
| 811 | + u8 upper_bins[3]; | |
| 812 | + u8 max_exp; | |
| 813 | +} __packed; | |
| 814 | + | |
| 815 | +#define SPECTRAL_HT20_40_NUM_BINS 128 | |
| 816 | + | |
| 817 | +/* WARNING: don't actually use this struct! MAC may vary the amount of | |
| 818 | + * data. This struct is for reference only. | |
| 819 | + */ | |
| 820 | +struct ath_ht20_40_fft_packet { | |
| 821 | + u8 data[SPECTRAL_HT20_40_NUM_BINS]; | |
| 822 | + struct ath_ht20_40_mag_info mag_info; | |
| 823 | + struct ath_radar_info radar_info; | |
| 824 | +} __packed; | |
| 825 | + | |
| 826 | + | |
| 827 | +#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet)) | |
| 828 | + | |
| 829 | +/* grabs the max magnitude from the all/upper/lower bins */ | |
| 830 | +static inline u16 spectral_max_magnitude(u8 *bins) | |
| 831 | +{ | |
| 832 | + return (bins[0] & 0xc0) >> 6 | | |
| 833 | + (bins[1] & 0xff) << 2 | | |
| 834 | + (bins[2] & 0x03) << 10; | |
| 835 | +} | |
| 836 | + | |
| 837 | +/* return the max magnitude from the all/upper/lower bins */ | |
| 838 | +static inline u8 spectral_max_index(u8 *bins) | |
| 839 | +{ | |
| 840 | + s8 m = (bins[2] & 0xfc) >> 2; | |
| 841 | + | |
| 842 | + /* TODO: this still doesn't always report the right values ... */ | |
| 843 | + if (m > 32) | |
| 844 | + m |= 0xe0; | |
| 845 | + else | |
| 846 | + m &= ~0xe0; | |
| 847 | + | |
| 848 | + return m + 29; | |
| 849 | +} | |
| 850 | + | |
| 851 | +/* return the bitmap weight from the all/upper/lower bins */ | |
| 852 | +static inline u8 spectral_bitmap_weight(u8 *bins) | |
| 853 | +{ | |
| 854 | + return bins[0] & 0x3f; | |
| 855 | +} | |
| 856 | + | |
| 857 | +/* FFT sample format given to userspace via debugfs. | |
| 858 | + * | |
| 859 | + * Please keep the type/length at the front position and change | |
| 860 | + * other fields after adding another sample type | |
| 861 | + * | |
| 862 | + * TODO: this might need rework when switching to nl80211-based | |
| 863 | + * interface. | |
| 864 | + */ | |
| 865 | +enum ath_fft_sample_type { | |
| 866 | + ATH_FFT_SAMPLE_HT20 = 0, | |
| 867 | +}; | |
| 868 | + | |
| 869 | +struct fft_sample_tlv { | |
| 870 | + u8 type; /* see ath_fft_sample */ | |
| 871 | + u16 length; | |
| 872 | + /* type dependent data follows */ | |
| 873 | +} __packed; | |
| 874 | + | |
| 875 | +struct fft_sample_ht20 { | |
| 876 | + struct fft_sample_tlv tlv; | |
| 877 | + | |
| 878 | + u8 __alignment; | |
| 879 | + | |
| 880 | + u16 freq; | |
| 881 | + s8 rssi; | |
| 882 | + s8 noise; | |
| 883 | + | |
| 884 | + u16 max_magnitude; | |
| 885 | + u8 max_index; | |
| 886 | + u8 bitmap_weight; | |
| 887 | + | |
| 888 | + u64 tsf; | |
| 889 | + | |
| 890 | + u16 data[SPECTRAL_HT20_NUM_BINS]; | |
| 891 | +} __packed; | |
| 892 | + | |
| 754 | 893 | void ath9k_tasklet(unsigned long data); |
| 755 | 894 | int ath_cabq_update(struct ath_softc *); |
| 756 | 895 | |
| @@ -773,6 +912,10 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); · 16 unmodified lines | ||
| 773 | 912 | void ath9k_reload_chainmask_settings(struct ath_softc *sc); |
| 774 | 913 | |
| 775 | 914 | bool ath9k_uses_beacons(int type); |
| 915 | +void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw); | |
| 916 | +int ath9k_spectral_scan_config(struct ieee80211_hw *hw, | |
| 917 | + enum spectral_mode spectral_mode); | |
| 918 | + | |
| 776 | 919 | |
| 777 | 920 | #ifdef CONFIG_ATH9K_PCI |
| 778 | 921 | int ath_pci_init(void); |
| @@ -147,6 +147,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, · 146 unmodified lines | ||
| 147 | 147 | skb->len, DMA_TO_DEVICE); |
| 148 | 148 | dev_kfree_skb_any(skb); |
| 149 | 149 | bf->bf_buf_addr = 0; |
| 150 | + bf->bf_mpdu = NULL; | |
| 150 | 151 | } |
| 151 | 152 | |
| 152 | 153 | skb = ieee80211_beacon_get(hw, vif); |
| @@ -198,7 +199,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, · 45 unmodified lines | ||
| 198 | 199 | if (sc->nvifs > 1) { |
| 199 | 200 | ath_dbg(common, BEACON, |
| 200 | 201 | "Flushing previous cabq traffic\n"); |
| 201 | − ath_draintxq(sc, cabq, false); | |
| 202 | + ath_draintxq(sc, cabq); | |
| 202 | 203 | } |
| 203 | 204 | } |
| 204 | 205 | |
| @@ -359,7 +360,6 @@ void ath9k_beacon_tasklet(unsigned long data) · 154 unmodified lines | ||
| 359 | 360 | return; |
| 360 | 361 | |
| 361 | 362 | bf = ath9k_beacon_generate(sc->hw, vif); |
| 362 | − WARN_ON(!bf); | |
| 363 | 363 | |
| 364 | 364 | if (sc->beacon.bmisscnt != 0) { |
| 365 | 365 | ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n", |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/slab.h> |
| 18 | 18 | #include <linux/vmalloc.h> |
| 19 | 19 | #include <linux/export.h> |
| 20 | +#include <linux/relay.h> | |
| 20 | 21 | #include <asm/unaligned.h> |
| 21 | 22 | |
| 22 | 23 | #include "ath9k.h" |
| @@ -861,7 +862,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, · 838 unmodified lines | ||
| 861 | 862 | RXS_ERR("RX-LENGTH-ERR", rx_len_err); |
| 862 | 863 | RXS_ERR("RX-OOM-ERR", rx_oom_err); |
| 863 | 864 | RXS_ERR("RX-RATE-ERR", rx_rate_err); |
| 864 | − RXS_ERR("RX-DROP-RXFLUSH", rx_drop_rxflush); | |
| 865 | 865 | RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err); |
| 866 | 866 | |
| 867 | 867 | PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); |
| @@ -966,6 +966,112 @@ static const struct file_operations fops_recv = { · 98 unmodified lines | ||
| 966 | 966 | .llseek = default_llseek, |
| 967 | 967 | }; |
| 968 | 968 | |
| 969 | +static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, | |
| 970 | + size_t count, loff_t *ppos) | |
| 971 | +{ | |
| 972 | + struct ath_softc *sc = file->private_data; | |
| 973 | + char *mode = ""; | |
| 974 | + unsigned int len; | |
| 975 | + | |
| 976 | + switch (sc->spectral_mode) { | |
| 977 | + case SPECTRAL_DISABLED: | |
| 978 | + mode = "disable"; | |
| 979 | + break; | |
| 980 | + case SPECTRAL_BACKGROUND: | |
| 981 | + mode = "background"; | |
| 982 | + break; | |
| 983 | + case SPECTRAL_CHANSCAN: | |
| 984 | + mode = "chanscan"; | |
| 985 | + break; | |
| 986 | + case SPECTRAL_MANUAL: | |
| 987 | + mode = "manual"; | |
| 988 | + break; | |
| 989 | + } | |
| 990 | + len = strlen(mode); | |
| 991 | + return simple_read_from_buffer(user_buf, count, ppos, mode, len); | |
| 992 | +} | |
| 993 | + | |
| 994 | +static ssize_t write_file_spec_scan_ctl(struct file *file, | |
| 995 | + const char __user *user_buf, | |
| 996 | + size_t count, loff_t *ppos) | |
| 997 | +{ | |
| 998 | + struct ath_softc *sc = file->private_data; | |
| 999 | + struct ath_common *common = ath9k_hw_common(sc->sc_ah); | |
| 1000 | + char buf[32]; | |
| 1001 | + ssize_t len; | |
| 1002 | + | |
| 1003 | + len = min(count, sizeof(buf) - 1); | |
| 1004 | + if (copy_from_user(buf, user_buf, len)) | |
| 1005 | + return -EFAULT; | |
| 1006 | + | |
| 1007 | + buf[len] = '\0'; | |
| 1008 | + | |
| 1009 | + if (strncmp("trigger", buf, 7) == 0) { | |
| 1010 | + ath9k_spectral_scan_trigger(sc->hw); | |
| 1011 | + } else if (strncmp("background", buf, 9) == 0) { | |
| 1012 | + ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND); | |
| 1013 | + ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n"); | |
| 1014 | + } else if (strncmp("chanscan", buf, 8) == 0) { | |
| 1015 | + ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN); | |
| 1016 | + ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n"); | |
| 1017 | + } else if (strncmp("manual", buf, 6) == 0) { | |
| 1018 | + ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL); | |
| 1019 | + ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n"); | |
| 1020 | + } else if (strncmp("disable", buf, 7) == 0) { | |
| 1021 | + ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED); | |
| 1022 | + ath_dbg(common, CONFIG, "spectral scan: disabled\n"); | |
| 1023 | + } else { | |
| 1024 | + return -EINVAL; | |
| 1025 | + } | |
| 1026 | + | |
| 1027 | + return count; | |
| 1028 | +} | |
| 1029 | + | |
| 1030 | +static const struct file_operations fops_spec_scan_ctl = { | |
| 1031 | + .read = read_file_spec_scan_ctl, | |
| 1032 | + .write = write_file_spec_scan_ctl, | |
| 1033 | + .open = simple_open, | |
| 1034 | + .owner = THIS_MODULE, | |
| 1035 | + .llseek = default_llseek, | |
| 1036 | +}; | |
| 1037 | + | |
| 1038 | +static struct dentry *create_buf_file_handler(const char *filename, | |
| 1039 | + struct dentry *parent, | |
| 1040 | + umode_t mode, | |
| 1041 | + struct rchan_buf *buf, | |
| 1042 | + int *is_global) | |
| 1043 | +{ | |
| 1044 | + struct dentry *buf_file; | |
| 1045 | + | |
| 1046 | + buf_file = debugfs_create_file(filename, mode, parent, buf, | |
| 1047 | + &relay_file_operations); | |
| 1048 | + *is_global = 1; | |
| 1049 | + return buf_file; | |
| 1050 | +} | |
| 1051 | + | |
| 1052 | +static int remove_buf_file_handler(struct dentry *dentry) | |
| 1053 | +{ | |
| 1054 | + debugfs_remove(dentry); | |
| 1055 | + | |
| 1056 | + return 0; | |
| 1057 | +} | |
| 1058 | + | |
| 1059 | +void ath_debug_send_fft_sample(struct ath_softc *sc, | |
| 1060 | + struct fft_sample_tlv *fft_sample_tlv) | |
| 1061 | +{ | |
| 1062 | + if (!sc->rfs_chan_spec_scan) | |
| 1063 | + return; | |
| 1064 | + | |
| 1065 | + relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, | |
| 1066 | + fft_sample_tlv->length + sizeof(*fft_sample_tlv)); | |
| 1067 | +} | |
| 1068 | + | |
| 1069 | +static struct rchan_callbacks rfs_spec_scan_cb = { | |
| 1070 | + .create_buf_file = create_buf_file_handler, | |
| 1071 | + .remove_buf_file = remove_buf_file_handler, | |
| 1072 | +}; | |
| 1073 | + | |
| 1074 | + | |
| 969 | 1075 | static ssize_t read_file_regidx(struct file *file, char __user *user_buf, |
| 970 | 1076 | size_t count, loff_t *ppos) |
| 971 | 1077 | { |
| @@ -1780,6 +1886,14 @@ int ath9k_init_debug(struct ath_hw *ah) · 808 unmodified lines | ||
| 1780 | 1886 | &fops_base_eeprom); |
| 1781 | 1887 | debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, |
| 1782 | 1888 | &fops_modal_eeprom); |
| 1889 | + sc->rfs_chan_spec_scan = relay_open("spectral_scan", | |
| 1890 | + sc->debug.debugfs_phy, | |
| 1891 | + 262144, 4, &rfs_spec_scan_cb, | |
| 1892 | + NULL); | |
| 1893 | + debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR, | |
| 1894 | + sc->debug.debugfs_phy, sc, | |
| 1895 | + &fops_spec_scan_ctl); | |
| 1896 | + | |
| 1783 | 1897 | #ifdef CONFIG_ATH9K_MAC_DEBUG |
| 1784 | 1898 | debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, |
| 1785 | 1899 | &fops_samps); |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | struct ath_txq; |
| 25 | 25 | struct ath_buf; |
| 26 | +struct fft_sample_tlv; | |
| 26 | 27 | |
| 27 | 28 | #ifdef CONFIG_ATH9K_DEBUGFS |
| 28 | 29 | #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ |
| @@ -216,7 +217,6 @@ struct ath_tx_stats { · 187 unmodified lines | ||
| 216 | 217 | * @rx_oom_err: No. of frames dropped due to OOM issues. |
| 217 | 218 | * @rx_rate_err: No. of frames dropped due to rate errors. |
| 218 | 219 | * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. |
| 219 | − * @rx_drop_rxflush: No. of frames dropped due to RX-FLUSH. | |
| 220 | 220 | * @rx_beacons: No. of beacons received. |
| 221 | 221 | * @rx_frags: No. of rx-fragements received. |
| 222 | 222 | */ |
| @@ -235,7 +235,6 @@ struct ath_rx_stats { · 12 unmodified lines | ||
| 235 | 235 | u32 rx_oom_err; |
| 236 | 236 | u32 rx_rate_err; |
| 237 | 237 | u32 rx_too_many_frags_err; |
| 238 | − u32 rx_drop_rxflush; | |
| 239 | 238 | u32 rx_beacons; |
| 240 | 239 | u32 rx_frags; |
| 241 | 240 | }; |
| @@ -323,6 +322,10 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, · 81 unmodified lines | ||
| 323 | 322 | struct ieee80211_vif *vif, |
| 324 | 323 | struct ieee80211_sta *sta, |
| 325 | 324 | struct dentry *dir); |
| 325 | + | |
| 326 | +void ath_debug_send_fft_sample(struct ath_softc *sc, | |
| 327 | + struct fft_sample_tlv *fft_sample); | |
| 328 | + | |
| 326 | 329 | #else |
| 327 | 330 | |
| 328 | 331 | #define RX_STAT_INC(c) /* NOP */ |
| @@ -344,6 +344,8 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, · 343 unmodified lines | ||
| 344 | 344 | endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv, |
| 345 | 345 | skb, htc_hdr->endpoint_id, |
| 346 | 346 | txok); |
| 347 | + } else { | |
| 348 | + kfree_skb(skb); | |
| 347 | 349 | } |
| 348 | 350 | } |
| 349 | 351 | |
| @@ -101,22 +101,6 @@ static inline void ath9k_hw_spur_mitigate_freq(struct ath_hw *ah, · 100 unmodified lines | ||
| 101 | 101 | ath9k_hw_private_ops(ah)->spur_mitigate_freq(ah, chan); |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | −static inline int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah) | |
| 105 | −{ | |
| 106 | − if (!ath9k_hw_private_ops(ah)->rf_alloc_ext_banks) | |
| 107 | − return 0; | |
| 108 | − | |
| 109 | − return ath9k_hw_private_ops(ah)->rf_alloc_ext_banks(ah); | |
| 110 | −} | |
| 111 | − | |
| 112 | −static inline void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah) | |
| 113 | −{ | |
| 114 | − if (!ath9k_hw_private_ops(ah)->rf_free_ext_banks) | |
| 115 | − return; | |
| 116 | − | |
| 117 | − ath9k_hw_private_ops(ah)->rf_free_ext_banks(ah); | |
| 118 | −} | |
| 119 | − | |
| 120 | 104 | static inline bool ath9k_hw_set_rf_regs(struct ath_hw *ah, |
| 121 | 105 | struct ath9k_channel *chan, |
| 122 | 106 | u16 modesIndex) |
| @@ -54,11 +54,6 @@ static void ath9k_hw_init_cal_settings(struct ath_hw *ah) · 53 unmodified lines | ||
| 54 | 54 | ath9k_hw_private_ops(ah)->init_cal_settings(ah); |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | −static void ath9k_hw_init_mode_regs(struct ath_hw *ah) | |
| 58 | −{ | |
| 59 | − ath9k_hw_private_ops(ah)->init_mode_regs(ah); | |
| 60 | −} | |
| 61 | − | |
| 62 | 57 | static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah, |
| 63 | 58 | struct ath9k_channel *chan) |
| 64 | 59 | { |
| @@ -208,7 +203,7 @@ void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan, · 143 unmodified lines | ||
| 208 | 203 | udelay(hw_delay + BASE_ACTIVATE_DELAY); |
| 209 | 204 | } |
| 210 | 205 | |
| 211 | −void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, | |
| 206 | +void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array, | |
| 212 | 207 | int column, unsigned int *writecnt) |
| 213 | 208 | { |
| 214 | 209 | int r; |
| @@ -554,28 +549,19 @@ static int ath9k_hw_post_init(struct ath_hw *ah) · 339 unmodified lines | ||
| 554 | 549 | ah->eep_ops->get_eeprom_ver(ah), |
| 555 | 550 | ah->eep_ops->get_eeprom_rev(ah)); |
| 556 | 551 | |
| 557 | − ecode = ath9k_hw_rf_alloc_ext_banks(ah); | |
| 558 | − if (ecode) { | |
| 559 | − ath_err(ath9k_hw_common(ah), | |
| 560 | − "Failed allocating banks for external radio\n"); | |
| 561 | − ath9k_hw_rf_free_ext_banks(ah); | |
| 562 | − return ecode; | |
| 563 | − } | |
| 564 | − | |
| 565 | − if (ah->config.enable_ani) { | |
| 566 | − ath9k_hw_ani_setup(ah); | |
| 552 | + if (ah->config.enable_ani) | |
| 567 | 553 | ath9k_hw_ani_init(ah); |
| 568 | − } | |
| 569 | 554 | |
| 570 | 555 | return 0; |
| 571 | 556 | } |
| 572 | 557 | |
| 573 | −static void ath9k_hw_attach_ops(struct ath_hw *ah) | |
| 558 | +static int ath9k_hw_attach_ops(struct ath_hw *ah) | |
| 574 | 559 | { |
| 575 | − if (AR_SREV_9300_20_OR_LATER(ah)) | |
| 576 | − ar9003_hw_attach_ops(ah); | |
| 577 | − else | |
| 578 | − ar9002_hw_attach_ops(ah); | |
| 560 | + if (!AR_SREV_9300_20_OR_LATER(ah)) | |
| 561 | + return ar9002_hw_attach_ops(ah); | |
| 562 | + | |
| 563 | + ar9003_hw_attach_ops(ah); | |
| 564 | + return 0; | |
| 579 | 565 | } |
| 580 | 566 | |
| 581 | 567 | /* Called for all hardware families */ |
| @@ -611,7 +597,9 @@ static int __ath9k_hw_init(struct ath_hw *ah) · 29 unmodified lines | ||
| 611 | 597 | ath9k_hw_init_defaults(ah); |
| 612 | 598 | ath9k_hw_init_config(ah); |
| 613 | 599 | |
| 614 | − ath9k_hw_attach_ops(ah); | |
| 600 | + r = ath9k_hw_attach_ops(ah); | |
| 601 | + if (r) | |
| 602 | + return r; | |
| 615 | 603 | |
| 616 | 604 | if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { |
| 617 | 605 | ath_err(common, "Couldn't wakeup chip\n"); |
| @@ -675,8 +663,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) · 57 unmodified lines | ||
| 675 | 663 | if (!AR_SREV_9300_20_OR_LATER(ah)) |
| 676 | 664 | ah->ani_function &= ~ATH9K_ANI_MRC_CCK; |
| 677 | 665 | |
| 678 | − ath9k_hw_init_mode_regs(ah); | |
| 679 | − | |
| 680 | 666 | if (!ah->is_pciexpress) |
| 681 | 667 | ath9k_hw_disablepcie(ah); |
| 682 | 668 | |
| @@ -1153,12 +1139,9 @@ void ath9k_hw_deinit(struct ath_hw *ah) · 470 unmodified lines | ||
| 1153 | 1139 | struct ath_common *common = ath9k_hw_common(ah); |
| 1154 | 1140 | |
| 1155 | 1141 | if (common->state < ATH_HW_INITIALIZED) |
| 1156 | − goto free_hw; | |
| 1142 | + return; | |
| 1157 | 1143 | |
| 1158 | 1144 | ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); |
| 1159 | − | |
| 1160 | −free_hw: | |
| 1161 | − ath9k_hw_rf_free_ext_banks(ah); | |
| 1162 | 1145 | } |
| 1163 | 1146 | EXPORT_SYMBOL(ath9k_hw_deinit); |
| 1164 | 1147 | |
| @@ -2576,12 +2559,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) · 1411 unmodified lines | ||
| 2576 | 2559 | rx_chainmask >>= 1; |
| 2577 | 2560 | } |
| 2578 | 2561 | |
| 2579 | − if (AR_SREV_9300_20_OR_LATER(ah)) { | |
| 2580 | − ah->enabled_cals |= TX_IQ_CAL; | |
| 2581 | − if (AR_SREV_9485_OR_LATER(ah)) | |
| 2582 | − ah->enabled_cals |= TX_IQ_ON_AGC_CAL; | |
| 2583 | − } | |
| 2584 | − | |
| 2585 | 2562 | if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { |
| 2586 | 2563 | if (!(ah->ent_mode & AR_ENT_OTP_49GHZ_DISABLE)) |
| 2587 | 2564 | pCap->hw_caps |= ATH9K_HW_CAP_MCI; |
| @@ -2590,7 +2567,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) · 2 unmodified lines | ||
| 2590 | 2567 | pCap->hw_caps |= ATH9K_HW_CAP_RTT; |
| 2591 | 2568 | } |
| 2592 | 2569 | |
| 2593 | − | |
| 2594 | 2570 | if (AR_SREV_9280_20_OR_LATER(ah)) { |
| 2595 | 2571 | pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE | |
| 2596 | 2572 | ATH9K_HW_WOW_PATTERN_MATCH_EXACT; |
| @@ -397,6 +397,7 @@ enum ath9k_int { · 396 unmodified lines | ||
| 397 | 397 | #define MAX_RTT_TABLE_ENTRY 6 |
| 398 | 398 | #define MAX_IQCAL_MEASUREMENT 8 |
| 399 | 399 | #define MAX_CL_TAB_ENTRY 16 |
| 400 | +#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j)) | |
| 400 | 401 | |
| 401 | 402 | struct ath9k_hw_cal_data { |
| 402 | 403 | u16 channel; |
| @@ -599,13 +600,10 @@ struct ath_hw_radar_conf { · 196 unmodified lines | ||
| 599 | 600 | * @init_cal_settings: setup types of calibrations supported |
| 600 | 601 | * @init_cal: starts actual calibration |
| 601 | 602 | * |
| 602 | − * @init_mode_regs: Initializes mode registers | |
| 603 | 603 | * @init_mode_gain_regs: Initialize TX/RX gain registers |
| 604 | 604 | * |
| 605 | 605 | * @rf_set_freq: change frequency |
| 606 | 606 | * @spur_mitigate_freq: spur mitigation |
| 607 | − * @rf_alloc_ext_banks: | |
| 608 | − * @rf_free_ext_banks: | |
| 609 | 607 | * @set_rf_regs: |
| 610 | 608 | * @compute_pll_control: compute the PLL control value to use for |
| 611 | 609 | * AR_RTC_PLL_CONTROL for a given channel |
| @@ -620,7 +618,6 @@ struct ath_hw_private_ops { · 8 unmodified lines | ||
| 620 | 618 | void (*init_cal_settings)(struct ath_hw *ah); |
| 621 | 619 | bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan); |
| 622 | 620 | |
| 623 | − void (*init_mode_regs)(struct ath_hw *ah); | |
| 624 | 621 | void (*init_mode_gain_regs)(struct ath_hw *ah); |
| 625 | 622 | void (*setup_calibration)(struct ath_hw *ah, |
| 626 | 623 | struct ath9k_cal_list *currCal); |
| @@ -630,8 +627,6 @@ struct ath_hw_private_ops { · 3 unmodified lines | ||
| 630 | 627 | struct ath9k_channel *chan); |
| 631 | 628 | void (*spur_mitigate_freq)(struct ath_hw *ah, |
| 632 | 629 | struct ath9k_channel *chan); |
| 633 | − int (*rf_alloc_ext_banks)(struct ath_hw *ah); | |
| 634 | − void (*rf_free_ext_banks)(struct ath_hw *ah); | |
| 635 | 630 | bool (*set_rf_regs)(struct ath_hw *ah, |
| 636 | 631 | struct ath9k_channel *chan, |
| 637 | 632 | u16 modesIndex); |
| @@ -660,6 +655,37 @@ struct ath_hw_private_ops { · 22 unmodified lines | ||
| 660 | 655 | void (*ani_cache_ini_regs)(struct ath_hw *ah); |
| 661 | 656 | }; |
| 662 | 657 | |
| 658 | +/** | |
| 659 | + * struct ath_spec_scan - parameters for Atheros spectral scan | |
| 660 | + * | |
| 661 | + * @enabled: enable/disable spectral scan | |
| 662 | + * @short_repeat: controls whether the chip is in spectral scan mode | |
| 663 | + * for 4 usec (enabled) or 204 usec (disabled) | |
| 664 | + * @count: number of scan results requested. There are special meanings | |
| 665 | + * in some chip revisions: | |
| 666 | + * AR92xx: highest bit set (>=128) for endless mode | |
| 667 | + * (spectral scan won't stopped until explicitly disabled) | |
| 668 | + * AR9300 and newer: 0 for endless mode | |
| 669 | + * @endless: true if endless mode is intended. Otherwise, count value is | |
| 670 | + * corrected to the next possible value. | |
| 671 | + * @period: time duration between successive spectral scan entry points | |
| 672 | + * (period*256*Tclk). Tclk = ath_common->clockrate | |
| 673 | + * @fft_period: PHY passes FFT frames to MAC every (fft_period+1)*4uS | |
| 674 | + * | |
| 675 | + * Note: Tclk = 40MHz or 44MHz depending upon operating mode. | |
| 676 | + * Typically it's 44MHz in 2/5GHz on later chips, but there's | |
| 677 | + * a "fast clock" check for this in 5GHz. | |
| 678 | + * | |
| 679 | + */ | |
| 680 | +struct ath_spec_scan { | |
| 681 | + bool enabled; | |
| 682 | + bool short_repeat; | |
| 683 | + bool endless; | |
| 684 | + u8 count; | |
| 685 | + u8 period; | |
| 686 | + u8 fft_period; | |
| 687 | +}; | |
| 688 | + | |
| 663 | 689 | /** |
| 664 | 690 | * struct ath_hw_ops - callbacks used by hardware code and driver code |
| 665 | 691 | * |
| @@ -668,6 +694,10 @@ struct ath_hw_private_ops { · 2 unmodified lines | ||
| 668 | 694 | * |
| 669 | 695 | * @config_pci_powersave: |
| 670 | 696 | * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC |
| 697 | + * | |
| 698 | + * @spectral_scan_config: set parameters for spectral scan and enable/disable it | |
| 699 | + * @spectral_scan_trigger: trigger a spectral scan run | |
| 700 | + * @spectral_scan_wait: wait for a spectral scan run to finish | |
| 671 | 701 | */ |
| 672 | 702 | struct ath_hw_ops { |
| 673 | 703 | void (*config_pci_powersave)(struct ath_hw *ah, |
| @@ -688,6 +718,10 @@ struct ath_hw_ops { · 14 unmodified lines | ||
| 688 | 718 | void (*antdiv_comb_conf_set)(struct ath_hw *ah, |
| 689 | 719 | struct ath_hw_antcomb_conf *antconf); |
| 690 | 720 | void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable); |
| 721 | + void (*spectral_scan_config)(struct ath_hw *ah, | |
| 722 | + struct ath_spec_scan *param); | |
| 723 | + void (*spectral_scan_trigger)(struct ath_hw *ah); | |
| 724 | + void (*spectral_scan_wait)(struct ath_hw *ah); | |
| 691 | 725 | }; |
| 692 | 726 | |
| 693 | 727 | struct ath_nf_limits { |
| @@ -710,6 +744,7 @@ enum ath_cal_list { · 16 unmodified lines | ||
| 710 | 744 | struct ath_hw { |
| 711 | 745 | struct ath_ops reg_ops; |
| 712 | 746 | |
| 747 | + struct device *dev; | |
| 713 | 748 | struct ieee80211_hw *hw; |
| 714 | 749 | struct ath_common common; |
| 715 | 750 | struct ath9k_hw_version hw_version; |
| @@ -771,7 +806,6 @@ struct ath_hw { · 55 unmodified lines | ||
| 771 | 806 | struct ath9k_cal_list iq_caldata; |
| 772 | 807 | struct ath9k_cal_list adcgain_caldata; |
| 773 | 808 | struct ath9k_cal_list adcdc_caldata; |
| 774 | − struct ath9k_cal_list tempCompCalData; | |
| 775 | 809 | struct ath9k_cal_list *cal_list; |
| 776 | 810 | struct ath9k_cal_list *cal_list_last; |
| 777 | 811 | struct ath9k_cal_list *cal_list_curr; |
| @@ -830,10 +864,6 @@ struct ath_hw { · 52 unmodified lines | ||
| 830 | 864 | /* ANI */ |
| 831 | 865 | u32 proc_phyerr; |
| 832 | 866 | u32 aniperiod; |
| 833 | − int totalSizeDesired[5]; | |
| 834 | − int coarse_high[5]; | |
| 835 | − int coarse_low[5]; | |
| 836 | − int firpwr[5]; | |
| 837 | 867 | enum ath9k_ani_cmd ani_function; |
| 838 | 868 | u32 ani_skip_count; |
| 839 | 869 | |
| @@ -979,7 +1009,7 @@ void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); · 139 unmodified lines | ||
| 979 | 1009 | void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan, |
| 980 | 1010 | int hw_delay); |
| 981 | 1011 | bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); |
| 982 | −void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, | |
| 1012 | +void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array, | |
| 983 | 1013 | int column, unsigned int *writecnt); |
| 984 | 1014 | u32 ath9k_hw_reverse_bits(u32 val, u32 n); |
| 985 | 1015 | u16 ath9k_hw_computetxtime(struct ath_hw *ah, |
| @@ -1066,16 +1096,17 @@ void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain); · 80 unmodified lines | ||
| 1066 | 1096 | int ar9003_paprd_init_table(struct ath_hw *ah); |
| 1067 | 1097 | bool ar9003_paprd_is_done(struct ath_hw *ah); |
| 1068 | 1098 | bool ar9003_is_paprd_enabled(struct ath_hw *ah); |
| 1099 | +void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); | |
| 1069 | 1100 | |
| 1070 | 1101 | /* Hardware family op attach helpers */ |
| 1071 | −void ar5008_hw_attach_phy_ops(struct ath_hw *ah); | |
| 1102 | +int ar5008_hw_attach_phy_ops(struct ath_hw *ah); | |
| 1072 | 1103 | void ar9002_hw_attach_phy_ops(struct ath_hw *ah); |
| 1073 | 1104 | void ar9003_hw_attach_phy_ops(struct ath_hw *ah); |
| 1074 | 1105 | |
| 1075 | 1106 | void ar9002_hw_attach_calib_ops(struct ath_hw *ah); |
| 1076 | 1107 | void ar9003_hw_attach_calib_ops(struct ath_hw *ah); |
| 1077 | 1108 | |
| 1078 | −void ar9002_hw_attach_ops(struct ath_hw *ah); | |
| 1109 | +int ar9002_hw_attach_ops(struct ath_hw *ah); | |
| 1079 | 1110 | void ar9003_hw_attach_ops(struct ath_hw *ah); |
| 1080 | 1111 | |
| 1081 | 1112 | void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <linux/slab.h> |
| 21 | 21 | #include <linux/ath9k_platform.h> |
| 22 | 22 | #include <linux/module.h> |
| 23 | +#include <linux/relay.h> | |
| 23 | 24 | |
| 24 | 25 | #include "ath9k.h" |
| 25 | 26 | |
| @@ -334,7 +335,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, · 308 unmodified lines | ||
| 334 | 335 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 335 | 336 | u8 *ds; |
| 336 | 337 | struct ath_buf *bf; |
| 337 | − int i, bsize, error, desc_len; | |
| 338 | + int i, bsize, desc_len; | |
| 338 | 339 | |
| 339 | 340 | ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n", |
| 340 | 341 | name, nbuf, ndesc); |
| @@ -350,8 +351,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, · 9 unmodified lines | ||
| 350 | 351 | if ((desc_len % 4) != 0) { |
| 351 | 352 | ath_err(common, "ath_desc not DWORD aligned\n"); |
| 352 | 353 | BUG_ON((desc_len % 4) != 0); |
| 353 | − error = -ENOMEM; | |
| 354 | − goto fail; | |
| 354 | + return -ENOMEM; | |
| 355 | 355 | } |
| 356 | 356 | |
| 357 | 357 | dd->dd_desc_len = desc_len * nbuf * ndesc; |
| @@ -375,12 +375,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, · 17 unmodified lines | ||
| 375 | 375 | } |
| 376 | 376 | |
| 377 | 377 | /* allocate descriptors */ |
| 378 | − dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, | |
| 379 | − &dd->dd_desc_paddr, GFP_KERNEL); | |
| 380 | − if (dd->dd_desc == NULL) { | |
| 381 | − error = -ENOMEM; | |
| 382 | − goto fail; | |
| 383 | − } | |
| 378 | + dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len, | |
| 379 | + &dd->dd_desc_paddr, GFP_KERNEL); | |
| 380 | + if (!dd->dd_desc) | |
| 381 | + return -ENOMEM; | |
| 382 | + | |
| 384 | 383 | ds = (u8 *) dd->dd_desc; |
| 385 | 384 | ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", |
| 386 | 385 | name, ds, (u32) dd->dd_desc_len, |
| @@ -388,12 +387,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, · 1 unmodified line | ||
| 388 | 387 | |
| 389 | 388 | /* allocate buffers */ |
| 390 | 389 | bsize = sizeof(struct ath_buf) * nbuf; |
| 391 | − bf = kzalloc(bsize, GFP_KERNEL); | |
| 392 | − if (bf == NULL) { | |
| 393 | − error = -ENOMEM; | |
| 394 | − goto fail2; | |
| 395 | − } | |
| 396 | − dd->dd_bufptr = bf; | |
| 390 | + bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); | |
| 391 | + if (!bf) | |
| 392 | + return -ENOMEM; | |
| 397 | 393 | |
| 398 | 394 | for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { |
| 399 | 395 | bf->bf_desc = ds; |
| @@ -419,12 +415,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, · 19 unmodified lines | ||
| 419 | 415 | list_add_tail(&bf->list, head); |
| 420 | 416 | } |
| 421 | 417 | return 0; |
| 422 | −fail2: | |
| 423 | − dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, | |
| 424 | − dd->dd_desc_paddr); | |
| 425 | −fail: | |
| 426 | − memset(dd, 0, sizeof(*dd)); | |
| 427 | − return error; | |
| 428 | 418 | } |
| 429 | 419 | |
| 430 | 420 | static int ath9k_init_queues(struct ath_softc *sc) |
| @@ -454,11 +444,13 @@ static int ath9k_init_channels_rates(struct ath_softc *sc) · 23 unmodified lines | ||
| 454 | 444 | ATH9K_NUM_CHANNELS); |
| 455 | 445 | |
| 456 | 446 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { |
| 457 | − channels = kmemdup(ath9k_2ghz_chantable, | |
| 447 | + channels = devm_kzalloc(sc->dev, | |
| 458 | 448 | sizeof(ath9k_2ghz_chantable), GFP_KERNEL); |
| 459 | 449 | if (!channels) |
| 460 | 450 | return -ENOMEM; |
| 461 | 451 | |
| 452 | + memcpy(channels, ath9k_2ghz_chantable, | |
| 453 | + sizeof(ath9k_2ghz_chantable)); | |
| 462 | 454 | sc->sbands[IEEE80211_BAND_2GHZ].channels = channels; |
| 463 | 455 | sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; |
| 464 | 456 | sc->sbands[IEEE80211_BAND_2GHZ].n_channels = |
| @@ -469,14 +461,13 @@ static int ath9k_init_channels_rates(struct ath_softc *sc) · 4 unmodified lines | ||
| 469 | 461 | } |
| 470 | 462 | |
| 471 | 463 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { |
| 472 | − channels = kmemdup(ath9k_5ghz_chantable, | |
| 464 | + channels = devm_kzalloc(sc->dev, | |
| 473 | 465 | sizeof(ath9k_5ghz_chantable), GFP_KERNEL); |
| 474 | − if (!channels) { | |
| 475 | − if (sc->sbands[IEEE80211_BAND_2GHZ].channels) | |
| 476 | − kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels); | |
| 466 | + if (!channels) | |
| 477 | 467 | return -ENOMEM; |
| 478 | − } | |
| 479 | 468 | |
| 469 | + memcpy(channels, ath9k_5ghz_chantable, | |
| 470 | + sizeof(ath9k_5ghz_chantable)); | |
| 480 | 471 | sc->sbands[IEEE80211_BAND_5GHZ].channels = channels; |
| 481 | 472 | sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; |
| 482 | 473 | sc->sbands[IEEE80211_BAND_5GHZ].n_channels = |
| @@ -562,10 +553,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, · 79 unmodified lines | ||
| 562 | 553 | int ret = 0, i; |
| 563 | 554 | int csz = 0; |
| 564 | 555 | |
| 565 | − ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); | |
| 556 | + ah = devm_kzalloc(sc->dev, sizeof(struct ath_hw), GFP_KERNEL); | |
| 566 | 557 | if (!ah) |
| 567 | 558 | return -ENOMEM; |
| 568 | 559 | |
| 560 | + ah->dev = sc->dev; | |
| 569 | 561 | ah->hw = sc->hw; |
| 570 | 562 | ah->hw_version.devid = devid; |
| 571 | 563 | ah->reg_ops.read = ath9k_ioread32; |
| @@ -633,7 +625,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, · 61 unmodified lines | ||
| 633 | 625 | if (pdata && pdata->eeprom_name) { |
| 634 | 626 | ret = ath9k_eeprom_request(sc, pdata->eeprom_name); |
| 635 | 627 | if (ret) |
| 636 | − goto err_eeprom; | |
| 628 | + return ret; | |
| 637 | 629 | } |
| 638 | 630 | |
| 639 | 631 | /* Initializes the hardware for all supported chipsets */ |
| @@ -673,10 +665,6 @@ err_queues: · 33 unmodified lines | ||
| 673 | 665 | ath9k_hw_deinit(ah); |
| 674 | 666 | err_hw: |
| 675 | 667 | ath9k_eeprom_release(sc); |
| 676 | −err_eeprom: | |
| 677 | − kfree(ah); | |
| 678 | − sc->sc_ah = NULL; | |
| 679 | − | |
| 680 | 668 | return ret; |
| 681 | 669 | } |
| 682 | 670 | |
| @@ -841,8 +829,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, · 158 unmodified lines | ||
| 841 | 829 | |
| 842 | 830 | /* Bring up device */ |
| 843 | 831 | error = ath9k_init_softc(devid, sc, bus_ops); |
| 844 | − if (error != 0) | |
| 845 | − goto error_init; | |
| 832 | + if (error) | |
| 833 | + return error; | |
| 846 | 834 | |
| 847 | 835 | ah = sc->sc_ah; |
| 848 | 836 | common = ath9k_hw_common(ah); |
| @@ -852,19 +840,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, · 3 unmodified lines | ||
| 852 | 840 | error = ath_regd_init(&common->regulatory, sc->hw->wiphy, |
| 853 | 841 | ath9k_reg_notifier); |
| 854 | 842 | if (error) |
| 855 | − goto error_regd; | |
| 843 | + goto deinit; | |
| 856 | 844 | |
| 857 | 845 | reg = &common->regulatory; |
| 858 | 846 | |
| 859 | 847 | /* Setup TX DMA */ |
| 860 | 848 | error = ath_tx_init(sc, ATH_TXBUF); |
| 861 | 849 | if (error != 0) |
| 862 | − goto error_tx; | |
| 850 | + goto deinit; | |
| 863 | 851 | |
| 864 | 852 | /* Setup RX DMA */ |
| 865 | 853 | error = ath_rx_init(sc, ATH_RXBUF); |
| 866 | 854 | if (error != 0) |
| 867 | − goto error_rx; | |
| 855 | + goto deinit; | |
| 868 | 856 | |
| 869 | 857 | ath9k_init_txpower_limits(sc); |
| 870 | 858 | |
| @@ -878,19 +866,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, · 7 unmodified lines | ||
| 878 | 866 | /* Register with mac80211 */ |
| 879 | 867 | error = ieee80211_register_hw(hw); |
| 880 | 868 | if (error) |
| 881 | − goto error_register; | |
| 869 | + goto rx_cleanup; | |
| 882 | 870 | |
| 883 | 871 | error = ath9k_init_debug(ah); |
| 884 | 872 | if (error) { |
| 885 | 873 | ath_err(common, "Unable to create debugfs files\n"); |
| 886 | − goto error_world; | |
| 874 | + goto unregister; | |
| 887 | 875 | } |
| 888 | 876 | |
| 889 | 877 | /* Handle world regulatory */ |
| 890 | 878 | if (!ath_is_world_regd(reg)) { |
| 891 | 879 | error = regulatory_hint(hw->wiphy, reg->alpha2); |
| 892 | 880 | if (error) |
| 893 | − goto error_world; | |
| 881 | + goto unregister; | |
| 894 | 882 | } |
| 895 | 883 | |
| 896 | 884 | ath_init_leds(sc); |
| @@ -898,17 +886,12 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, · 1 unmodified line | ||
| 898 | 886 | |
| 899 | 887 | return 0; |
| 900 | 888 | |
| 901 | −error_world: | |
| 889 | +unregister: | |
| 902 | 890 | ieee80211_unregister_hw(hw); |
| 903 | −error_register: | |
| 891 | +rx_cleanup: | |
| 904 | 892 | ath_rx_cleanup(sc); |
| 905 | −error_rx: | |
| 906 | − ath_tx_cleanup(sc); | |
| 907 | −error_tx: | |
| 908 | − /* Nothing */ | |
| 909 | −error_regd: | |
| 893 | +deinit: | |
| 910 | 894 | ath9k_deinit_softc(sc); |
| 911 | −error_init: | |
| 912 | 895 | return error; |
| 913 | 896 | } |
| 914 | 897 | |
| @@ -920,12 +903,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc) · 5 unmodified lines | ||
| 920 | 903 | { |
| 921 | 904 | int i = 0; |
| 922 | 905 | |
| 923 | − if (sc->sbands[IEEE80211_BAND_2GHZ].channels) | |
| 924 | − kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels); | |
| 925 | − | |
| 926 | − if (sc->sbands[IEEE80211_BAND_5GHZ].channels) | |
| 927 | − kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels); | |
| 928 | − | |
| 929 | 906 | ath9k_deinit_btcoex(sc); |
| 930 | 907 | |
| 931 | 908 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) |
| @@ -937,8 +914,11 @@ static void ath9k_deinit_softc(struct ath_softc *sc) · 5 unmodified lines | ||
| 937 | 914 | sc->dfs_detector->exit(sc->dfs_detector); |
| 938 | 915 | |
| 939 | 916 | ath9k_eeprom_release(sc); |
| 940 | − kfree(sc->sc_ah); | |
| 941 | − sc->sc_ah = NULL; | |
| 917 | + | |
| 918 | + if (sc->rfs_chan_spec_scan) { | |
| 919 | + relay_close(sc->rfs_chan_spec_scan); | |
| 920 | + sc->rfs_chan_spec_scan = NULL; | |
| 921 | + } | |
| 942 | 922 | } |
| 943 | 923 | |
| 944 | 924 | void ath9k_deinit_device(struct ath_softc *sc) |
| @@ -954,22 +934,9 @@ void ath9k_deinit_device(struct ath_softc *sc) · 9 unmodified lines | ||
| 954 | 934 | |
| 955 | 935 | ieee80211_unregister_hw(hw); |
| 956 | 936 | ath_rx_cleanup(sc); |
| 957 | − ath_tx_cleanup(sc); | |
| 958 | 937 | ath9k_deinit_softc(sc); |
| 959 | 938 | } |
| 960 | 939 | |
| 961 | −void ath_descdma_cleanup(struct ath_softc *sc, | |
| 962 | − struct ath_descdma *dd, | |
| 963 | − struct list_head *head) | |
| 964 | −{ | |
| 965 | − dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, | |
| 966 | − dd->dd_desc_paddr); | |
| 967 | − | |
| 968 | − INIT_LIST_HEAD(head); | |
| 969 | − kfree(dd->dd_bufptr); | |
| 970 | − memset(dd, 0, sizeof(*dd)); | |
| 971 | −} | |
| 972 | − | |
| 973 | 940 | /************************/ |
| 974 | 941 | /* Module Hooks */ |
| 975 | 942 | /************************/ |
| @@ -226,7 +226,8 @@ enum ath9k_phyerr { · 225 unmodified lines | ||
| 226 | 226 | ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35, |
| 227 | 227 | ATH9K_PHYERR_HT_RATE_ILLEGAL = 36, |
| 228 | 228 | |
| 229 | − ATH9K_PHYERR_MAX = 37, | |
| 229 | + ATH9K_PHYERR_SPECTRAL = 38, | |
| 230 | + ATH9K_PHYERR_MAX = 39, | |
| 230 | 231 | }; |
| 231 | 232 | |
| 232 | 233 | struct ath_desc { |
| @@ -182,7 +182,7 @@ static void ath_restart_work(struct ath_softc *sc) · 181 unmodified lines | ||
| 182 | 182 | ath_start_ani(sc); |
| 183 | 183 | } |
| 184 | 184 | |
| 185 | −static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) | |
| 185 | +static bool ath_prepare_reset(struct ath_softc *sc) | |
| 186 | 186 | { |
| 187 | 187 | struct ath_hw *ah = sc->sc_ah; |
| 188 | 188 | bool ret = true; |
| @@ -196,20 +196,12 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) · 7 unmodified lines | ||
| 196 | 196 | ath9k_debug_samp_bb_mac(sc); |
| 197 | 197 | ath9k_hw_disable_interrupts(ah); |
| 198 | 198 | |
| 199 | − if (!ath_stoprecv(sc)) | |
| 199 | + if (!ath_drain_all_txq(sc)) | |
| 200 | 200 | ret = false; |
| 201 | 201 | |
| 202 | − if (!ath_drain_all_txq(sc, retry_tx)) | |
| 202 | + if (!ath_stoprecv(sc)) | |
| 203 | 203 | ret = false; |
| 204 | 204 | |
| 205 | − if (!flush) { | |
| 206 | − if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | |
| 207 | − ath_rx_tasklet(sc, 1, true); | |
| 208 | − ath_rx_tasklet(sc, 1, false); | |
| 209 | − } else { | |
| 210 | − ath_flushrecv(sc); | |
| 211 | − } | |
| 212 | − | |
| 213 | 205 | return ret; |
| 214 | 206 | } |
| 215 | 207 | |
| @@ -255,18 +247,17 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) · 39 unmodified lines | ||
| 255 | 247 | return true; |
| 256 | 248 | } |
| 257 | 249 | |
| 258 | −static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, | |
| 259 | − bool retry_tx) | |
| 250 | +static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) | |
| 260 | 251 | { |
| 261 | 252 | struct ath_hw *ah = sc->sc_ah; |
| 262 | 253 | struct ath_common *common = ath9k_hw_common(ah); |
| 263 | 254 | struct ath9k_hw_cal_data *caldata = NULL; |
| 264 | 255 | bool fastcc = true; |
| 265 | − bool flush = false; | |
| 266 | 256 | int r; |
| 267 | 257 | |
| 268 | 258 | __ath_cancel_work(sc); |
| 269 | 259 | |
| 260 | + tasklet_disable(&sc->intr_tq); | |
| 270 | 261 | spin_lock_bh(&sc->sc_pcu_lock); |
| 271 | 262 | |
| 272 | 263 | if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { |
| @@ -276,11 +267,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, · 3 unmodified lines | ||
| 276 | 267 | |
| 277 | 268 | if (!hchan) { |
| 278 | 269 | fastcc = false; |
| 279 | − flush = true; | |
| 280 | 270 | hchan = ah->curchan; |
| 281 | 271 | } |
| 282 | 272 | |
| 283 | − if (!ath_prepare_reset(sc, retry_tx, flush)) | |
| 273 | + if (!ath_prepare_reset(sc)) | |
| 284 | 274 | fastcc = false; |
| 285 | 275 | |
| 286 | 276 | ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", |
| @@ -302,6 +292,8 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, · 15 unmodified lines | ||
| 302 | 292 | |
| 303 | 293 | out: |
| 304 | 294 | spin_unlock_bh(&sc->sc_pcu_lock); |
| 295 | + tasklet_enable(&sc->intr_tq); | |
| 296 | + | |
| 305 | 297 | return r; |
| 306 | 298 | } |
| 307 | 299 | |
| @@ -319,7 +311,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, · 11 unmodified lines | ||
| 319 | 311 | if (test_bit(SC_OP_INVALID, &sc->sc_flags)) |
| 320 | 312 | return -EIO; |
| 321 | 313 | |
| 322 | − r = ath_reset_internal(sc, hchan, false); | |
| 314 | + r = ath_reset_internal(sc, hchan); | |
| 323 | 315 | |
| 324 | 316 | return r; |
| 325 | 317 | } |
| @@ -549,23 +541,21 @@ chip_reset: · 223 unmodified lines | ||
| 549 | 541 | #undef SCHED_INTR |
| 550 | 542 | } |
| 551 | 543 | |
| 552 | −static int ath_reset(struct ath_softc *sc, bool retry_tx) | |
| 544 | +static int ath_reset(struct ath_softc *sc) | |
| 553 | 545 | { |
| 554 | − int r; | |
| 546 | + int i, r; | |
| 555 | 547 | |
| 556 | 548 | ath9k_ps_wakeup(sc); |
| 557 | 549 | |
| 558 | − r = ath_reset_internal(sc, NULL, retry_tx); | |
| 550 | + r = ath_reset_internal(sc, NULL); | |
| 559 | 551 | |
| 560 | − if (retry_tx) { | |
| 561 | − int i; | |
| 562 | − for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { | |
| 563 | − if (ATH_TXQ_SETUP(sc, i)) { | |
| 564 | − spin_lock_bh(&sc->tx.txq[i].axq_lock); | |
| 565 | − ath_txq_schedule(sc, &sc->tx.txq[i]); | |
| 566 | − spin_unlock_bh(&sc->tx.txq[i].axq_lock); | |
| 567 | − } | |
| 568 | − } | |
| 552 | + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { | |
| 553 | + if (!ATH_TXQ_SETUP(sc, i)) | |
| 554 | + continue; | |
| 555 | + | |
| 556 | + spin_lock_bh(&sc->tx.txq[i].axq_lock); | |
| 557 | + ath_txq_schedule(sc, &sc->tx.txq[i]); | |
| 558 | + spin_unlock_bh(&sc->tx.txq[i].axq_lock); | |
| 569 | 559 | } |
| 570 | 560 | |
| 571 | 561 | ath9k_ps_restore(sc); |
| @@ -586,7 +576,7 @@ void ath_reset_work(struct work_struct *work) · 14 unmodified lines | ||
| 586 | 576 | { |
| 587 | 577 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); |
| 588 | 578 | |
| 589 | − ath_reset(sc, true); | |
| 579 | + ath_reset(sc); | |
| 590 | 580 | } |
| 591 | 581 | |
| 592 | 582 | /**********************/ |
| @@ -804,7 +794,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) · 211 unmodified lines | ||
| 804 | 794 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); |
| 805 | 795 | } |
| 806 | 796 | |
| 807 | − ath_prepare_reset(sc, false, true); | |
| 797 | + ath_prepare_reset(sc); | |
| 808 | 798 | |
| 809 | 799 | if (sc->rx.frag) { |
| 810 | 800 | dev_kfree_skb_any(sc->rx.frag); |
| @@ -1075,6 +1065,86 @@ static void ath9k_disable_ps(struct ath_softc *sc) · 264 unmodified lines | ||
| 1075 | 1065 | ath_dbg(common, PS, "PowerSave disabled\n"); |
| 1076 | 1066 | } |
| 1077 | 1067 | |
| 1068 | +void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw) | |
| 1069 | +{ | |
| 1070 | + struct ath_softc *sc = hw->priv; | |
| 1071 | + struct ath_hw *ah = sc->sc_ah; | |
| 1072 | + struct ath_common *common = ath9k_hw_common(ah); | |
| 1073 | + u32 rxfilter; | |
| 1074 | + | |
| 1075 | + if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { | |
| 1076 | + ath_err(common, "spectrum analyzer not implemented on this hardware\n"); | |
| 1077 | + return; | |
| 1078 | + } | |
| 1079 | + | |
| 1080 | + ath9k_ps_wakeup(sc); | |
| 1081 | + rxfilter = ath9k_hw_getrxfilter(ah); | |
| 1082 | + ath9k_hw_setrxfilter(ah, rxfilter | | |
| 1083 | + ATH9K_RX_FILTER_PHYRADAR | | |
| 1084 | + ATH9K_RX_FILTER_PHYERR); | |
| 1085 | + | |
| 1086 | + /* TODO: usually this should not be neccesary, but for some reason | |
| 1087 | + * (or in some mode?) the trigger must be called after the | |
| 1088 | + * configuration, otherwise the register will have its values reset | |
| 1089 | + * (on my ar9220 to value 0x01002310) | |
| 1090 | + */ | |
| 1091 | + ath9k_spectral_scan_config(hw, sc->spectral_mode); | |
| 1092 | + ath9k_hw_ops(ah)->spectral_scan_trigger(ah); | |
| 1093 | + ath9k_ps_restore(sc); | |
| 1094 | +} | |
| 1095 | + | |
| 1096 | +int ath9k_spectral_scan_config(struct ieee80211_hw *hw, | |
| 1097 | + enum spectral_mode spectral_mode) | |
| 1098 | +{ | |
| 1099 | + struct ath_softc *sc = hw->priv; | |
| 1100 | + struct ath_hw *ah = sc->sc_ah; | |
| 1101 | + struct ath_common *common = ath9k_hw_common(ah); | |
| 1102 | + struct ath_spec_scan param; | |
| 1103 | + | |
| 1104 | + if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { | |
| 1105 | + ath_err(common, "spectrum analyzer not implemented on this hardware\n"); | |
| 1106 | + return -1; | |
| 1107 | + } | |
| 1108 | + | |
| 1109 | + /* NOTE: this will generate a few samples ... | |
| 1110 | + * | |
| 1111 | + * TODO: review default parameters, and/or define an interface to set | |
| 1112 | + * them. | |
| 1113 | + */ | |
| 1114 | + param.enabled = 1; | |
| 1115 | + param.short_repeat = true; | |
| 1116 | + param.count = 8; | |
| 1117 | + param.endless = false; | |
| 1118 | + param.period = 0xFF; | |
| 1119 | + param.fft_period = 0xF; | |
| 1120 | + | |
| 1121 | + switch (spectral_mode) { | |
| 1122 | + case SPECTRAL_DISABLED: | |
| 1123 | + param.enabled = 0; | |
| 1124 | + break; | |
| 1125 | + case SPECTRAL_BACKGROUND: | |
| 1126 | + /* send endless samples. | |
| 1127 | + * TODO: is this really useful for "background"? | |
| 1128 | + */ | |
| 1129 | + param.endless = 1; | |
| 1130 | + break; | |
| 1131 | + case SPECTRAL_CHANSCAN: | |
| 1132 | + break; | |
| 1133 | + case SPECTRAL_MANUAL: | |
| 1134 | + break; | |
| 1135 | + default: | |
| 1136 | + return -1; | |
| 1137 | + } | |
| 1138 | + | |
| 1139 | + ath9k_ps_wakeup(sc); | |
| 1140 | + ath9k_hw_ops(ah)->spectral_scan_config(ah, ¶m); | |
| 1141 | + ath9k_ps_restore(sc); | |
| 1142 | + | |
| 1143 | + sc->spectral_mode = spectral_mode; | |
| 1144 | + | |
| 1145 | + return 0; | |
| 1146 | +} | |
| 1147 | + | |
| 1078 | 1148 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) |
| 1079 | 1149 | { |
| 1080 | 1150 | struct ath_softc *sc = hw->priv; |
| @@ -1188,6 +1258,11 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) · 107 unmodified lines | ||
| 1188 | 1258 | */ |
| 1189 | 1259 | if (old_pos >= 0) |
| 1190 | 1260 | ath_update_survey_nf(sc, old_pos); |
| 1261 | + | |
| 1262 | + /* perform spectral scan if requested. */ | |
| 1263 | + if (sc->scanning && sc->spectral_mode == SPECTRAL_CHANSCAN) | |
| 1264 | + ath9k_spectral_scan_trigger(hw); | |
| 1265 | + | |
| 1191 | 1266 | } |
| 1192 | 1267 | |
| 1193 | 1268 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |
| @@ -1731,11 +1806,11 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) · 537 unmodified lines | ||
| 1731 | 1806 | if (drop) { |
| 1732 | 1807 | ath9k_ps_wakeup(sc); |
| 1733 | 1808 | spin_lock_bh(&sc->sc_pcu_lock); |
| 1734 | − drain_txq = ath_drain_all_txq(sc, false); | |
| 1809 | + drain_txq = ath_drain_all_txq(sc); | |
| 1735 | 1810 | spin_unlock_bh(&sc->sc_pcu_lock); |
| 1736 | 1811 | |
| 1737 | 1812 | if (!drain_txq) |
| 1738 | − ath_reset(sc, false); | |
| 1813 | + ath_reset(sc); | |
| 1739 | 1814 | |
| 1740 | 1815 | ath9k_ps_restore(sc); |
| 1741 | 1816 | ieee80211_wake_queues(hw); |
| @@ -1835,6 +1910,9 @@ static u32 fill_chainmask(u32 cap, u32 new) · 93 unmodified lines | ||
| 1835 | 1910 | |
| 1836 | 1911 | static bool validate_antenna_mask(struct ath_hw *ah, u32 val) |
| 1837 | 1912 | { |
| 1913 | + if (AR_SREV_9300_20_OR_LATER(ah)) | |
| 1914 | + return true; | |
| 1915 | + | |
| 1838 | 1916 | switch (val & 0x7) { |
| 1839 | 1917 | case 0x1: |
| 1840 | 1918 | case 0x3: |
| @@ -2240,6 +2318,19 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) · 399 unmodified lines | ||
| 2240 | 2318 | } |
| 2241 | 2319 | |
| 2242 | 2320 | #endif |
| 2321 | +static void ath9k_sw_scan_start(struct ieee80211_hw *hw) | |
| 2322 | +{ | |
| 2323 | + struct ath_softc *sc = hw->priv; | |
| 2324 | + | |
| 2325 | + sc->scanning = 1; | |
| 2326 | +} | |
| 2327 | + | |
| 2328 | +static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) | |
| 2329 | +{ | |
| 2330 | + struct ath_softc *sc = hw->priv; | |
| 2331 | + | |
| 2332 | + sc->scanning = 0; | |
| 2333 | +} | |
| 2243 | 2334 | |
| 2244 | 2335 | struct ieee80211_ops ath9k_ops = { |
| 2245 | 2336 | .tx = ath9k_tx, |
| @@ -2286,4 +2377,6 @@ struct ieee80211_ops ath9k_ops = { · 40 unmodified lines | ||
| 2286 | 2377 | .sta_add_debugfs = ath9k_sta_add_debugfs, |
| 2287 | 2378 | .sta_remove_debugfs = ath9k_sta_remove_debugfs, |
| 2288 | 2379 | #endif |
| 2380 | + .sw_scan_start = ath9k_sw_scan_start, | |
| 2381 | + .sw_scan_complete = ath9k_sw_scan_complete, | |
| 2289 | 2382 | }; |
| @@ -438,7 +438,7 @@ int ath_mci_setup(struct ath_softc *sc) · 437 unmodified lines | ||
| 438 | 438 | struct ath_mci_buf *buf = &mci->sched_buf; |
| 439 | 439 | int ret; |
| 440 | 440 | |
| 441 | − buf->bf_addr = dma_alloc_coherent(sc->dev, | |
| 441 | + buf->bf_addr = dmam_alloc_coherent(sc->dev, | |
| 442 | 442 | ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE, |
| 443 | 443 | &buf->bf_paddr, GFP_KERNEL); |
| 444 | 444 | |
| @@ -477,11 +477,6 @@ void ath_mci_cleanup(struct ath_softc *sc) · 32 unmodified lines | ||
| 477 | 477 | struct ath_mci_coex *mci = &sc->mci_coex; |
| 478 | 478 | struct ath_mci_buf *buf = &mci->sched_buf; |
| 479 | 479 | |
| 480 | − if (buf->bf_addr) | |
| 481 | − dma_free_coherent(sc->dev, | |
| 482 | − ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE, | |
| 483 | − buf->bf_addr, buf->bf_paddr); | |
| 484 | − | |
| 485 | 480 | ar9003_mci_cleanup(ah); |
| 486 | 481 | |
| 487 | 482 | ath_dbg(common, MCI, "MCI De-Initialized\n"); |
| @@ -147,7 +147,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = { · 146 unmodified lines | ||
| 147 | 147 | |
| 148 | 148 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| 149 | 149 | { |
| 150 | − void __iomem *mem; | |
| 151 | 150 | struct ath_softc *sc; |
| 152 | 151 | struct ieee80211_hw *hw; |
| 153 | 152 | u8 csz; |
| @@ -155,19 +154,19 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 1 unmodified line | ||
| 155 | 154 | int ret = 0; |
| 156 | 155 | char hw_name[64]; |
| 157 | 156 | |
| 158 | − if (pci_enable_device(pdev)) | |
| 157 | + if (pcim_enable_device(pdev)) | |
| 159 | 158 | return -EIO; |
| 160 | 159 | |
| 161 | 160 | ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); |
| 162 | 161 | if (ret) { |
| 163 | 162 | pr_err("32-bit DMA not available\n"); |
| 164 | − goto err_dma; | |
| 163 | + return ret; | |
| 165 | 164 | } |
| 166 | 165 | |
| 167 | 166 | ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); |
| 168 | 167 | if (ret) { |
| 169 | 168 | pr_err("32-bit DMA consistent DMA enable failed\n"); |
| 170 | − goto err_dma; | |
| 169 | + return ret; | |
| 171 | 170 | } |
| 172 | 171 | |
| 173 | 172 | /* |
| @@ -203,25 +202,16 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 29 unmodified lines | ||
| 203 | 202 | if ((val & 0x0000ff00) != 0) |
| 204 | 203 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); |
| 205 | 204 | |
| 206 | − ret = pci_request_region(pdev, 0, "ath9k"); | |
| 205 | + ret = pcim_iomap_regions(pdev, BIT(0), "ath9k"); | |
| 207 | 206 | if (ret) { |
| 208 | 207 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); |
| 209 | − ret = -ENODEV; | |
| 210 | − goto err_region; | |
| 211 | − } | |
| 212 | − | |
| 213 | − mem = pci_iomap(pdev, 0, 0); | |
| 214 | − if (!mem) { | |
| 215 | − pr_err("PCI memory map error\n") ; | |
| 216 | − ret = -EIO; | |
| 217 | − goto err_iomap; | |
| 208 | + return -ENODEV; | |
| 218 | 209 | } |
| 219 | 210 | |
| 220 | 211 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); |
| 221 | 212 | if (!hw) { |
| 222 | 213 | dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); |
| 223 | − ret = -ENOMEM; | |
| 224 | − goto err_alloc_hw; | |
| 214 | + return -ENOMEM; | |
| 225 | 215 | } |
| 226 | 216 | |
| 227 | 217 | SET_IEEE80211_DEV(hw, &pdev->dev); |
| @@ -230,7 +220,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 2 unmodified lines | ||
| 230 | 220 | sc = hw->priv; |
| 231 | 221 | sc->hw = hw; |
| 232 | 222 | sc->dev = &pdev->dev; |
| 233 | − sc->mem = mem; | |
| 223 | + sc->mem = pcim_iomap_table(pdev)[0]; | |
| 234 | 224 | |
| 235 | 225 | /* Will be cleared in ath9k_start() */ |
| 236 | 226 | set_bit(SC_OP_INVALID, &sc->sc_flags); |
| @@ -251,7 +241,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 14 unmodified lines | ||
| 251 | 241 | |
| 252 | 242 | ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name)); |
| 253 | 243 | wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", |
| 254 | − hw_name, (unsigned long)mem, pdev->irq); | |
| 244 | + hw_name, (unsigned long)sc->mem, pdev->irq); | |
| 255 | 245 | |
| 256 | 246 | return 0; |
| 257 | 247 | |
| @@ -259,14 +249,6 @@ err_init: · 1 unmodified line | ||
| 259 | 249 | free_irq(sc->irq, sc); |
| 260 | 250 | err_irq: |
| 261 | 251 | ieee80211_free_hw(hw); |
| 262 | −err_alloc_hw: | |
| 263 | − pci_iounmap(pdev, mem); | |
| 264 | −err_iomap: | |
| 265 | − pci_release_region(pdev, 0); | |
| 266 | −err_region: | |
| 267 | − /* Nothing */ | |
| 268 | −err_dma: | |
| 269 | − pci_disable_device(pdev); | |
| 270 | 252 | return ret; |
| 271 | 253 | } |
| 272 | 254 | |
| @@ -274,17 +256,12 @@ static void ath_pci_remove(struct pci_dev *pdev) · 1 unmodified line | ||
| 274 | 256 | { |
| 275 | 257 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
| 276 | 258 | struct ath_softc *sc = hw->priv; |
| 277 | − void __iomem *mem = sc->mem; | |
| 278 | 259 | |
| 279 | 260 | if (!is_ath9k_unloaded) |
| 280 | 261 | sc->sc_ah->ah_flags |= AH_UNPLUGGED; |
| 281 | 262 | ath9k_deinit_device(sc); |
| 282 | 263 | free_irq(sc->irq, sc); |
| 283 | 264 | ieee80211_free_hw(sc->hw); |
| 284 | − | |
| 285 | − pci_iounmap(pdev, mem); | |
| 286 | − pci_disable_device(pdev); | |
| 287 | − pci_release_region(pdev, 0); | |
| 288 | 265 | } |
| 289 | 266 | |
| 290 | 267 | #ifdef CONFIG_PM_SLEEP |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | */ |
| 16 | 16 | |
| 17 | 17 | #include <linux/dma-mapping.h> |
| 18 | +#include <linux/relay.h> | |
| 18 | 19 | #include "ath9k.h" |
| 19 | 20 | #include "ar9003_mac.h" |
| 20 | 21 | |
| @@ -180,11 +181,6 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc) · 159 unmodified lines | ||
| 180 | 181 | bf->bf_mpdu = NULL; |
| 181 | 182 | } |
| 182 | 183 | } |
| 183 | − | |
| 184 | − INIT_LIST_HEAD(&sc->rx.rxbuf); | |
| 185 | − | |
| 186 | − kfree(sc->rx.rx_bufptr); | |
| 187 | − sc->rx.rx_bufptr = NULL; | |
| 188 | 184 | } |
| 189 | 185 | |
| 190 | 186 | static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size) |
| @@ -211,12 +207,11 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs) · 20 unmodified lines | ||
| 211 | 207 | ah->caps.rx_hp_qdepth); |
| 212 | 208 | |
| 213 | 209 | size = sizeof(struct ath_buf) * nbufs; |
| 214 | − bf = kzalloc(size, GFP_KERNEL); | |
| 210 | + bf = devm_kzalloc(sc->dev, size, GFP_KERNEL); | |
| 215 | 211 | if (!bf) |
| 216 | 212 | return -ENOMEM; |
| 217 | 213 | |
| 218 | 214 | INIT_LIST_HEAD(&sc->rx.rxbuf); |
| 219 | − sc->rx.rx_bufptr = bf; | |
| 220 | 215 | |
| 221 | 216 | for (i = 0; i < nbufs; i++, bf++) { |
| 222 | 217 | skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL); |
| @@ -254,8 +249,6 @@ rx_init_fail: · 31 unmodified lines | ||
| 254 | 249 | |
| 255 | 250 | static void ath_edma_start_recv(struct ath_softc *sc) |
| 256 | 251 | { |
| 257 | − spin_lock_bh(&sc->rx.rxbuflock); | |
| 258 | − | |
| 259 | 252 | ath9k_hw_rxena(sc->sc_ah); |
| 260 | 253 | |
| 261 | 254 | ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP, |
| @@ -267,8 +260,6 @@ static void ath_edma_start_recv(struct ath_softc *sc) · 5 unmodified lines | ||
| 267 | 260 | ath_opmode_init(sc); |
| 268 | 261 | |
| 269 | 262 | ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); |
| 270 | − | |
| 271 | − spin_unlock_bh(&sc->rx.rxbuflock); | |
| 272 | 263 | } |
| 273 | 264 | |
| 274 | 265 | static void ath_edma_stop_recv(struct ath_softc *sc) |
| @@ -285,8 +276,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) · 10 unmodified lines | ||
| 285 | 276 | int error = 0; |
| 286 | 277 | |
| 287 | 278 | spin_lock_init(&sc->sc_pcu_lock); |
| 288 | − spin_lock_init(&sc->rx.rxbuflock); | |
| 289 | − clear_bit(SC_OP_RXFLUSH, &sc->sc_flags); | |
| 290 | 279 | |
| 291 | 280 | common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + |
| 292 | 281 | sc->sc_ah->caps.rx_status_len; |
| @@ -363,9 +352,6 @@ void ath_rx_cleanup(struct ath_softc *sc) · 70 unmodified lines | ||
| 363 | 352 | bf->bf_mpdu = NULL; |
| 364 | 353 | } |
| 365 | 354 | } |
| 366 | − | |
| 367 | − if (sc->rx.rxdma.dd_desc_len != 0) | |
| 368 | − ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf); | |
| 369 | 355 | } |
| 370 | 356 | } |
| 371 | 357 | |
| @@ -447,7 +433,6 @@ int ath_startrecv(struct ath_softc *sc) · 75 unmodified lines | ||
| 447 | 433 | return 0; |
| 448 | 434 | } |
| 449 | 435 | |
| 450 | − spin_lock_bh(&sc->rx.rxbuflock); | |
| 451 | 436 | if (list_empty(&sc->rx.rxbuf)) |
| 452 | 437 | goto start_recv; |
| 453 | 438 | |
| @@ -468,26 +453,31 @@ start_recv: · 14 unmodified lines | ||
| 468 | 453 | ath_opmode_init(sc); |
| 469 | 454 | ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); |
| 470 | 455 | |
| 471 | − spin_unlock_bh(&sc->rx.rxbuflock); | |
| 472 | − | |
| 473 | 456 | return 0; |
| 474 | 457 | } |
| 475 | 458 | |
| 459 | +static void ath_flushrecv(struct ath_softc *sc) | |
| 460 | +{ | |
| 461 | + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | |
| 462 | + ath_rx_tasklet(sc, 1, true); | |
| 463 | + ath_rx_tasklet(sc, 1, false); | |
| 464 | +} | |
| 465 | + | |
| 476 | 466 | bool ath_stoprecv(struct ath_softc *sc) |
| 477 | 467 | { |
| 478 | 468 | struct ath_hw *ah = sc->sc_ah; |
| 479 | 469 | bool stopped, reset = false; |
| 480 | 470 | |
| 481 | − spin_lock_bh(&sc->rx.rxbuflock); | |
| 482 | 471 | ath9k_hw_abortpcurecv(ah); |
| 483 | 472 | ath9k_hw_setrxfilter(ah, 0); |
| 484 | 473 | stopped = ath9k_hw_stopdmarecv(ah, &reset); |
| 485 | 474 | |
| 475 | + ath_flushrecv(sc); | |
| 476 | + | |
| 486 | 477 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
| 487 | 478 | ath_edma_stop_recv(sc); |
| 488 | 479 | else |
| 489 | 480 | sc->rx.rxlink = NULL; |
| 490 | − spin_unlock_bh(&sc->rx.rxbuflock); | |
| 491 | 481 | |
| 492 | 482 | if (!(ah->ah_flags & AH_UNPLUGGED) && |
| 493 | 483 | unlikely(!stopped)) { |
| @@ -499,15 +489,6 @@ bool ath_stoprecv(struct ath_softc *sc) · 5 unmodified lines | ||
| 499 | 489 | return stopped && !reset; |
| 500 | 490 | } |
| 501 | 491 | |
| 502 | −void ath_flushrecv(struct ath_softc *sc) | |
| 503 | −{ | |
| 504 | − set_bit(SC_OP_RXFLUSH, &sc->sc_flags); | |
| 505 | − if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | |
| 506 | − ath_rx_tasklet(sc, 1, true); | |
| 507 | − ath_rx_tasklet(sc, 1, false); | |
| 508 | − clear_bit(SC_OP_RXFLUSH, &sc->sc_flags); | |
| 509 | −} | |
| 510 | − | |
| 511 | 492 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) |
| 512 | 493 | { |
| 513 | 494 | /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ |
| @@ -744,6 +725,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, · 230 unmodified lines | ||
| 744 | 725 | return NULL; |
| 745 | 726 | } |
| 746 | 727 | |
| 728 | + list_del(&bf->list); | |
| 747 | 729 | if (!bf->bf_mpdu) |
| 748 | 730 | return bf; |
| 749 | 731 | |
| @@ -1034,6 +1016,108 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common, · 284 unmodified lines | ||
| 1034 | 1016 | rxs->flag &= ~RX_FLAG_DECRYPTED; |
| 1035 | 1017 | } |
| 1036 | 1018 | |
| 1019 | +static s8 fix_rssi_inv_only(u8 rssi_val) | |
| 1020 | +{ | |
| 1021 | + if (rssi_val == 128) | |
| 1022 | + rssi_val = 0; | |
| 1023 | + return (s8) rssi_val; | |
| 1024 | +} | |
| 1025 | + | |
| 1026 | + | |
| 1027 | +static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, | |
| 1028 | + struct ath_rx_status *rs, u64 tsf) | |
| 1029 | +{ | |
| 1030 | +#ifdef CONFIG_ATH_DEBUG | |
| 1031 | + struct ath_hw *ah = sc->sc_ah; | |
| 1032 | + u8 bins[SPECTRAL_HT20_NUM_BINS]; | |
| 1033 | + u8 *vdata = (u8 *)hdr; | |
| 1034 | + struct fft_sample_ht20 fft_sample; | |
| 1035 | + struct ath_radar_info *radar_info; | |
| 1036 | + struct ath_ht20_mag_info *mag_info; | |
| 1037 | + int len = rs->rs_datalen; | |
| 1038 | + int i, dc_pos; | |
| 1039 | + | |
| 1040 | + /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer | |
| 1041 | + * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT | |
| 1042 | + * yet, but this is supposed to be possible as well. | |
| 1043 | + */ | |
| 1044 | + if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && | |
| 1045 | + rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && | |
| 1046 | + rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) | |
| 1047 | + return; | |
| 1048 | + | |
| 1049 | + /* Variation in the data length is possible and will be fixed later. | |
| 1050 | + * Note that we only support HT20 for now. | |
| 1051 | + * | |
| 1052 | + * TODO: add HT20_40 support as well. | |
| 1053 | + */ | |
| 1054 | + if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || | |
| 1055 | + (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) | |
| 1056 | + return; | |
| 1057 | + | |
| 1058 | + /* check if spectral scan bit is set. This does not have to be checked | |
| 1059 | + * if received through a SPECTRAL phy error, but shouldn't hurt. | |
| 1060 | + */ | |
| 1061 | + radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; | |
| 1062 | + if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) | |
| 1063 | + return; | |
| 1064 | + | |
| 1065 | + fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; | |
| 1066 | + fft_sample.tlv.length = sizeof(fft_sample) - sizeof(fft_sample.tlv); | |
| 1067 | + | |
| 1068 | + fft_sample.freq = ah->curchan->chan->center_freq; | |
| 1069 | + fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); | |
| 1070 | + fft_sample.noise = ah->noise; | |
| 1071 | + | |
| 1072 | + switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) { | |
| 1073 | + case 0: | |
| 1074 | + /* length correct, nothing to do. */ | |
| 1075 | + memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS); | |
| 1076 | + break; | |
| 1077 | + case -1: | |
| 1078 | + /* first byte missing, duplicate it. */ | |
| 1079 | + memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1); | |
| 1080 | + bins[0] = vdata[0]; | |
| 1081 | + break; | |
| 1082 | + case 2: | |
| 1083 | + /* MAC added 2 extra bytes at bin 30 and 32, remove them. */ | |
| 1084 | + memcpy(bins, vdata, 30); | |
| 1085 | + bins[30] = vdata[31]; | |
| 1086 | + memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31); | |
| 1087 | + break; | |
| 1088 | + case 1: | |
| 1089 | + /* MAC added 2 extra bytes AND first byte is missing. */ | |
| 1090 | + bins[0] = vdata[0]; | |
| 1091 | + memcpy(&bins[0], vdata, 30); | |
| 1092 | + bins[31] = vdata[31]; | |
| 1093 | + memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); | |
| 1094 | + break; | |
| 1095 | + default: | |
| 1096 | + return; | |
| 1097 | + } | |
| 1098 | + | |
| 1099 | + /* DC value (value in the middle) is the blind spot of the spectral | |
| 1100 | + * sample and invalid, interpolate it. | |
| 1101 | + */ | |
| 1102 | + dc_pos = SPECTRAL_HT20_NUM_BINS / 2; | |
| 1103 | + bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2; | |
| 1104 | + | |
| 1105 | + /* mag data is at the end of the frame, in front of radar_info */ | |
| 1106 | + mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; | |
| 1107 | + | |
| 1108 | + /* Apply exponent and grab further auxiliary information. */ | |
| 1109 | + for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) | |
| 1110 | + fft_sample.data[i] = bins[i] << mag_info->max_exp; | |
| 1111 | + | |
| 1112 | + fft_sample.max_magnitude = spectral_max_magnitude(mag_info->all_bins); | |
| 1113 | + fft_sample.max_index = spectral_max_index(mag_info->all_bins); | |
| 1114 | + fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); | |
| 1115 | + fft_sample.tsf = tsf; | |
| 1116 | + | |
| 1117 | + ath_debug_send_fft_sample(sc, &fft_sample.tlv); | |
| 1118 | +#endif | |
| 1119 | +} | |
| 1120 | + | |
| 1037 | 1121 | int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) |
| 1038 | 1122 | { |
| 1039 | 1123 | struct ath_buf *bf; |
| @@ -1059,16 +1143,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) · 19 unmodified lines | ||
| 1059 | 1143 | dma_type = DMA_FROM_DEVICE; |
| 1060 | 1144 | |
| 1061 | 1145 | qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP; |
| 1062 | − spin_lock_bh(&sc->rx.rxbuflock); | |
| 1063 | 1146 | |
| 1064 | 1147 | tsf = ath9k_hw_gettsf64(ah); |
| 1065 | 1148 | tsf_lower = tsf & 0xffffffff; |
| 1066 | 1149 | |
| 1067 | 1150 | do { |
| 1068 | 1151 | bool decrypt_error = false; |
| 1069 | − /* If handling rx interrupt and flush is in progress => exit */ | |
| 1070 | − if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0)) | |
| 1071 | − break; | |
| 1072 | 1152 | |
| 1073 | 1153 | memset(&rs, 0, sizeof(rs)); |
| 1074 | 1154 | if (edma) |
| @@ -1111,15 +1191,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) · 36 unmodified lines | ||
| 1111 | 1191 | |
| 1112 | 1192 | ath_debug_stat_rx(sc, &rs); |
| 1113 | 1193 | |
| 1114 | − /* | |
| 1115 | − * If we're asked to flush receive queue, directly | |
| 1116 | − * chain it back at the queue without processing it. | |
| 1117 | − */ | |
| 1118 | − if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) { | |
| 1119 | − RX_STAT_INC(rx_drop_rxflush); | |
| 1120 | − goto requeue_drop_frag; | |
| 1121 | − } | |
| 1122 | − | |
| 1123 | 1194 | memset(rxs, 0, sizeof(struct ieee80211_rx_status)); |
| 1124 | 1195 | |
| 1125 | 1196 | rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; |
| @@ -1131,6 +1202,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) · 5 unmodified lines | ||
| 1131 | 1202 | unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) |
| 1132 | 1203 | rxs->mactime += 0x100000000ULL; |
| 1133 | 1204 | |
| 1205 | + if ((rs.rs_status & ATH9K_RXERR_PHY)) | |
| 1206 | + ath_process_fft(sc, hdr, &rs, rxs->mactime); | |
| 1207 | + | |
| 1134 | 1208 | retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, |
| 1135 | 1209 | rxs, &decrypt_error); |
| 1136 | 1210 | if (retval) |
| @@ -1254,19 +1328,18 @@ requeue_drop_frag: · 117 unmodified lines | ||
| 1254 | 1328 | sc->rx.frag = NULL; |
| 1255 | 1329 | } |
| 1256 | 1330 | requeue: |
| 1331 | + list_add_tail(&bf->list, &sc->rx.rxbuf); | |
| 1332 | + if (flush) | |
| 1333 | + continue; | |
| 1334 | + | |
| 1257 | 1335 | if (edma) { |
| 1258 | − list_add_tail(&bf->list, &sc->rx.rxbuf); | |
| 1259 | 1336 | ath_rx_edma_buf_link(sc, qtype); |
| 1260 | 1337 | } else { |
| 1261 | − list_move_tail(&bf->list, &sc->rx.rxbuf); | |
| 1262 | 1338 | ath_rx_buf_link(sc, bf); |
| 1263 | − if (!flush) | |
| 1264 | − ath9k_hw_rxena(ah); | |
| 1339 | + ath9k_hw_rxena(ah); | |
| 1265 | 1340 | } |
| 1266 | 1341 | } while (1); |
| 1267 | 1342 | |
| 1268 | − spin_unlock_bh(&sc->rx.rxbuflock); | |
| 1269 | − | |
| 1270 | 1343 | if (!(ah->imask & ATH9K_INT_RXEOL)) { |
| 1271 | 1344 | ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN); |
| 1272 | 1345 | ath9k_hw_set_interrupts(ah); |
| @@ -789,6 +789,7 @@ · 788 unmodified lines | ||
| 789 | 789 | #define AR_SREV_REVISION_9271_11 1 |
| 790 | 790 | #define AR_SREV_VERSION_9300 0x1c0 |
| 791 | 791 | #define AR_SREV_REVISION_9300_20 2 /* 2.0 and 2.1 */ |
| 792 | +#define AR_SREV_REVISION_9300_22 3 | |
| 792 | 793 | #define AR_SREV_VERSION_9330 0x200 |
| 793 | 794 | #define AR_SREV_REVISION_9330_10 0 |
| 794 | 795 | #define AR_SREV_REVISION_9330_11 1 |
| @@ -869,6 +870,9 @@ · 74 unmodified lines | ||
| 869 | 870 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300)) |
| 870 | 871 | #define AR_SREV_9300_20_OR_LATER(_ah) \ |
| 871 | 872 | ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300) |
| 873 | +#define AR_SREV_9300_22(_ah) \ | |
| 874 | + (AR_SREV_9300(ah) && \ | |
| 875 | + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_22)) | |
| 872 | 876 | |
| 873 | 877 | #define AR_SREV_9330(_ah) \ |
| 874 | 878 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9330)) |
| @@ -884,9 +888,6 @@ · 9 unmodified lines | ||
| 884 | 888 | |
| 885 | 889 | #define AR_SREV_9485(_ah) \ |
| 886 | 890 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) |
| 887 | −#define AR_SREV_9485_10(_ah) \ | |
| 888 | − (AR_SREV_9485(_ah) && \ | |
| 889 | − ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_10)) | |
| 890 | 891 | #define AR_SREV_9485_11(_ah) \ |
| 891 | 892 | (AR_SREV_9485(_ah) && \ |
| 892 | 893 | ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11)) |
| @@ -378,7 +378,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, · 377 unmodified lines | ||
| 378 | 378 | |
| 379 | 379 | static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, |
| 380 | 380 | struct ath_buf *bf, struct list_head *bf_q, |
| 381 | − struct ath_tx_status *ts, int txok, bool retry) | |
| 381 | + struct ath_tx_status *ts, int txok) | |
| 382 | 382 | { |
| 383 | 383 | struct ath_node *an = NULL; |
| 384 | 384 | struct sk_buff *skb; |
| @@ -490,7 +490,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, · 105 unmodified lines | ||
| 490 | 490 | } else if (!isaggr && txok) { |
| 491 | 491 | /* transmit completion */ |
| 492 | 492 | acked_cnt++; |
| 493 | − } else if ((tid->state & AGGR_CLEANUP) || !retry) { | |
| 493 | + } else if (tid->state & AGGR_CLEANUP) { | |
| 494 | 494 | /* |
| 495 | 495 | * cleanup in progress, just fail |
| 496 | 496 | * the un-acked sub-frames |
| @@ -604,6 +604,37 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, · 107 unmodified lines | ||
| 604 | 604 | ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR); |
| 605 | 605 | } |
| 606 | 606 | |
| 607 | +static bool bf_is_ampdu_not_probing(struct ath_buf *bf) | |
| 608 | +{ | |
| 609 | + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu); | |
| 610 | + return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); | |
| 611 | +} | |
| 612 | + | |
| 613 | +static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, | |
| 614 | + struct ath_tx_status *ts, struct ath_buf *bf, | |
| 615 | + struct list_head *bf_head) | |
| 616 | +{ | |
| 617 | + bool txok, flush; | |
| 618 | + | |
| 619 | + txok = !(ts->ts_status & ATH9K_TXERR_MASK); | |
| 620 | + flush = !!(ts->ts_status & ATH9K_TX_FLUSH); | |
| 621 | + txq->axq_tx_inprogress = false; | |
| 622 | + | |
| 623 | + txq->axq_depth--; | |
| 624 | + if (bf_is_ampdu_not_probing(bf)) | |
| 625 | + txq->axq_ampdu_depth--; | |
| 626 | + | |
| 627 | + if (!bf_isampdu(bf)) { | |
| 628 | + if (!flush) | |
| 629 | + ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); | |
| 630 | + ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); | |
| 631 | + } else | |
| 632 | + ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok); | |
| 633 | + | |
| 634 | + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !flush) | |
| 635 | + ath_txq_schedule(sc, txq); | |
| 636 | +} | |
| 637 | + | |
| 607 | 638 | static bool ath_lookup_legacy(struct ath_buf *bf) |
| 608 | 639 | { |
| 609 | 640 | struct sk_buff *skb; |
| @@ -1331,23 +1362,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid · 721 unmodified lines | ||
| 1331 | 1362 | /* Queue Management */ |
| 1332 | 1363 | /********************/ |
| 1333 | 1364 | |
| 1334 | −static void ath_txq_drain_pending_buffers(struct ath_softc *sc, | |
| 1335 | − struct ath_txq *txq) | |
| 1336 | −{ | |
| 1337 | − struct ath_atx_ac *ac, *ac_tmp; | |
| 1338 | − struct ath_atx_tid *tid, *tid_tmp; | |
| 1339 | − | |
| 1340 | − list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { | |
| 1341 | − list_del(&ac->list); | |
| 1342 | − ac->sched = false; | |
| 1343 | − list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) { | |
| 1344 | − list_del(&tid->list); | |
| 1345 | − tid->sched = false; | |
| 1346 | − ath_tid_drain(sc, txq, tid); | |
| 1347 | − } | |
| 1348 | − } | |
| 1349 | −} | |
| 1350 | − | |
| 1351 | 1365 | struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) |
| 1352 | 1366 | { |
| 1353 | 1367 | struct ath_hw *ah = sc->sc_ah; |
| @@ -1470,14 +1484,8 @@ int ath_cabq_update(struct ath_softc *sc) · 116 unmodified lines | ||
| 1470 | 1484 | return 0; |
| 1471 | 1485 | } |
| 1472 | 1486 | |
| 1473 | −static bool bf_is_ampdu_not_probing(struct ath_buf *bf) | |
| 1474 | −{ | |
| 1475 | − struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu); | |
| 1476 | − return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); | |
| 1477 | −} | |
| 1478 | − | |
| 1479 | 1487 | static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, |
| 1480 | − struct list_head *list, bool retry_tx) | |
| 1488 | + struct list_head *list) | |
| 1481 | 1489 | { |
| 1482 | 1490 | struct ath_buf *bf, *lastbf; |
| 1483 | 1491 | struct list_head bf_head; |
| @@ -1499,16 +1507,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, · 15 unmodified lines | ||
| 1499 | 1507 | |
| 1500 | 1508 | lastbf = bf->bf_lastbf; |
| 1501 | 1509 | list_cut_position(&bf_head, list, &lastbf->list); |
| 1502 | − | |
| 1503 | − txq->axq_depth--; | |
| 1504 | − if (bf_is_ampdu_not_probing(bf)) | |
| 1505 | − txq->axq_ampdu_depth--; | |
| 1506 | − | |
| 1507 | − if (bf_isampdu(bf)) | |
| 1508 | − ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0, | |
| 1509 | − retry_tx); | |
| 1510 | − else | |
| 1511 | − ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); | |
| 1510 | + ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); | |
| 1512 | 1511 | } |
| 1513 | 1512 | } |
| 1514 | 1513 | |
| @@ -1518,7 +1517,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, · 3 unmodified lines | ||
| 1518 | 1517 | * This assumes output has been stopped and |
| 1519 | 1518 | * we do not need to block ath_tx_tasklet. |
| 1520 | 1519 | */ |
| 1521 | −void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) | |
| 1520 | +void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq) | |
| 1522 | 1521 | { |
| 1523 | 1522 | ath_txq_lock(sc, txq); |
| 1524 | 1523 | |
| @@ -1526,8 +1525,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) · 1 unmodified line | ||
| 1526 | 1525 | int idx = txq->txq_tailidx; |
| 1527 | 1526 | |
| 1528 | 1527 | while (!list_empty(&txq->txq_fifo[idx])) { |
| 1529 | − ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx], | |
| 1530 | − retry_tx); | |
| 1528 | + ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx]); | |
| 1531 | 1529 | |
| 1532 | 1530 | INCR(idx, ATH_TXFIFO_DEPTH); |
| 1533 | 1531 | } |
| @@ -1536,16 +1534,12 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) · 2 unmodified lines | ||
| 1536 | 1534 | |
| 1537 | 1535 | txq->axq_link = NULL; |
| 1538 | 1536 | txq->axq_tx_inprogress = false; |
| 1539 | − ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx); | |
| 1540 | − | |
| 1541 | − /* flush any pending frames if aggregation is enabled */ | |
| 1542 | − if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !retry_tx) | |
| 1543 | − ath_txq_drain_pending_buffers(sc, txq); | |
| 1537 | + ath_drain_txq_list(sc, txq, &txq->axq_q); | |
| 1544 | 1538 | |
| 1545 | 1539 | ath_txq_unlock_complete(sc, txq); |
| 1546 | 1540 | } |
| 1547 | 1541 | |
| 1548 | −bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) | |
| 1542 | +bool ath_drain_all_txq(struct ath_softc *sc) | |
| 1549 | 1543 | { |
| 1550 | 1544 | struct ath_hw *ah = sc->sc_ah; |
| 1551 | 1545 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| @@ -1581,7 +1575,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) · 29 unmodified lines | ||
| 1581 | 1575 | */ |
| 1582 | 1576 | txq = &sc->tx.txq[i]; |
| 1583 | 1577 | txq->stopped = false; |
| 1584 | − ath_draintxq(sc, txq, retry_tx); | |
| 1578 | + ath_draintxq(sc, txq); | |
| 1585 | 1579 | } |
| 1586 | 1580 | |
| 1587 | 1581 | return !npend; |
| @@ -2175,28 +2169,6 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, · 587 unmodified lines | ||
| 2175 | 2169 | tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1; |
| 2176 | 2170 | } |
| 2177 | 2171 | |
| 2178 | −static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, | |
| 2179 | − struct ath_tx_status *ts, struct ath_buf *bf, | |
| 2180 | − struct list_head *bf_head) | |
| 2181 | −{ | |
| 2182 | − int txok; | |
| 2183 | − | |
| 2184 | − txq->axq_depth--; | |
| 2185 | − txok = !(ts->ts_status & ATH9K_TXERR_MASK); | |
| 2186 | − txq->axq_tx_inprogress = false; | |
| 2187 | − if (bf_is_ampdu_not_probing(bf)) | |
| 2188 | − txq->axq_ampdu_depth--; | |
| 2189 | − | |
| 2190 | − if (!bf_isampdu(bf)) { | |
| 2191 | − ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); | |
| 2192 | − ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); | |
| 2193 | − } else | |
| 2194 | − ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true); | |
| 2195 | − | |
| 2196 | − if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) | |
| 2197 | − ath_txq_schedule(sc, txq); | |
| 2198 | −} | |
| 2199 | − | |
| 2200 | 2172 | static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) |
| 2201 | 2173 | { |
| 2202 | 2174 | struct ath_hw *ah = sc->sc_ah; |
| @@ -2361,8 +2333,8 @@ static int ath_txstatus_setup(struct ath_softc *sc, int size) · 158 unmodified lines | ||
| 2361 | 2333 | u8 txs_len = sc->sc_ah->caps.txs_len; |
| 2362 | 2334 | |
| 2363 | 2335 | dd->dd_desc_len = size * txs_len; |
| 2364 | − dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, | |
| 2365 | − &dd->dd_desc_paddr, GFP_KERNEL); | |
| 2336 | + dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len, | |
| 2337 | + &dd->dd_desc_paddr, GFP_KERNEL); | |
| 2366 | 2338 | if (!dd->dd_desc) |
| 2367 | 2339 | return -ENOMEM; |
| 2368 | 2340 | |
| @@ -2382,14 +2354,6 @@ static int ath_tx_edma_init(struct ath_softc *sc) · 13 unmodified lines | ||
| 2382 | 2354 | return err; |
| 2383 | 2355 | } |
| 2384 | 2356 | |
| 2385 | −static void ath_tx_edma_cleanup(struct ath_softc *sc) | |
| 2386 | −{ | |
| 2387 | − struct ath_descdma *dd = &sc->txsdma; | |
| 2388 | − | |
| 2389 | − dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, | |
| 2390 | − dd->dd_desc_paddr); | |
| 2391 | −} | |
| 2392 | − | |
| 2393 | 2357 | int ath_tx_init(struct ath_softc *sc, int nbufs) |
| 2394 | 2358 | { |
| 2395 | 2359 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| @@ -2402,7 +2366,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) · 6 unmodified lines | ||
| 2402 | 2366 | if (error != 0) { |
| 2403 | 2367 | ath_err(common, |
| 2404 | 2368 | "Failed to allocate tx descriptors: %d\n", error); |
| 2405 | − goto err; | |
| 2369 | + return error; | |
| 2406 | 2370 | } |
| 2407 | 2371 | |
| 2408 | 2372 | error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, |
| @@ -2410,36 +2374,17 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) · 1 unmodified line | ||
| 2410 | 2374 | if (error != 0) { |
| 2411 | 2375 | ath_err(common, |
| 2412 | 2376 | "Failed to allocate beacon descriptors: %d\n", error); |
| 2413 | − goto err; | |
| 2377 | + return error; | |
| 2414 | 2378 | } |
| 2415 | 2379 | |
| 2416 | 2380 | INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); |
| 2417 | 2381 | |
| 2418 | − if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { | |
| 2382 | + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | |
| 2419 | 2383 | error = ath_tx_edma_init(sc); |
| 2420 | − if (error) | |
| 2421 | − goto err; | |
| 2422 | − } | |
| 2423 | − | |
| 2424 | −err: | |
| 2425 | − if (error != 0) | |
| 2426 | − ath_tx_cleanup(sc); | |
| 2427 | 2384 | |
| 2428 | 2385 | return error; |
| 2429 | 2386 | } |
| 2430 | 2387 | |
| 2431 | −void ath_tx_cleanup(struct ath_softc *sc) | |
| 2432 | −{ | |
| 2433 | − if (sc->beacon.bdma.dd_desc_len != 0) | |
| 2434 | − ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); | |
| 2435 | − | |
| 2436 | − if (sc->tx.txdma.dd_desc_len != 0) | |
| 2437 | − ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); | |
| 2438 | − | |
| 2439 | − if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | |
| 2440 | − ath_tx_edma_cleanup(sc); | |
| 2441 | −} | |
| 2442 | − | |
| 2443 | 2388 | void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) |
| 2444 | 2389 | { |
| 2445 | 2390 | struct ath_atx_tid *tid; |
| @@ -85,20 +85,14 @@ enum carl9170_device_state { · 84 unmodified lines | ||
| 85 | 85 | CARL9170_STARTED, |
| 86 | 86 | }; |
| 87 | 87 | |
| 88 | −#define CARL9170_NUM_TID 16 | |
| 89 | 88 | #define WME_BA_BMP_SIZE 64 |
| 90 | 89 | #define CARL9170_TX_USER_RATE_TRIES 3 |
| 91 | 90 | |
| 92 | −#define WME_AC_BE 2 | |
| 93 | −#define WME_AC_BK 3 | |
| 94 | −#define WME_AC_VI 1 | |
| 95 | −#define WME_AC_VO 0 | |
| 96 | − | |
| 97 | 91 | #define TID_TO_WME_AC(_tid) \ |
| 98 | − ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ | |
| 99 | − (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ | |
| 100 | − (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ | |
| 101 | − WME_AC_VO) | |
| 92 | + ((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE : \ | |
| 93 | + (((_tid) == 1) || ((_tid) == 2)) ? IEEE80211_AC_BK : \ | |
| 94 | + (((_tid) == 4) || ((_tid) == 5)) ? IEEE80211_AC_VI : \ | |
| 95 | + IEEE80211_AC_VO) | |
| 102 | 96 | |
| 103 | 97 | #define SEQ_DIFF(_start, _seq) \ |
| 104 | 98 | (((_start) - (_seq)) & 0x0fff) |
| @@ -290,6 +284,7 @@ struct ar9170 { · 185 unmodified lines | ||
| 290 | 284 | unsigned int rx_size; |
| 291 | 285 | unsigned int tx_seq_table; |
| 292 | 286 | bool ba_filter; |
| 287 | + bool disable_offload_fw; | |
| 293 | 288 | } fw; |
| 294 | 289 | |
| 295 | 290 | /* interface configuration combinations */ |
| @@ -493,8 +488,8 @@ struct carl9170_sta_info { · 197 unmodified lines | ||
| 493 | 488 | bool sleeping; |
| 494 | 489 | atomic_t pending_frames; |
| 495 | 490 | unsigned int ampdu_max_len; |
| 496 | − struct carl9170_sta_tid __rcu *agg[CARL9170_NUM_TID]; | |
| 497 | − struct carl9170_ba_stats stats[CARL9170_NUM_TID]; | |
| 491 | + struct carl9170_sta_tid __rcu *agg[IEEE80211_NUM_TIDS]; | |
| 492 | + struct carl9170_ba_stats stats[IEEE80211_NUM_TIDS]; | |
| 498 | 493 | }; |
| 499 | 494 | |
| 500 | 495 | struct carl9170_tx_info { |
| @@ -215,6 +215,24 @@ static int carl9170_fw_tx_sequence(struct ar9170 *ar) · 214 unmodified lines | ||
| 215 | 215 | return 0; |
| 216 | 216 | } |
| 217 | 217 | |
| 218 | +static void carl9170_fw_set_if_combinations(struct ar9170 *ar, | |
| 219 | + u16 if_comb_types) | |
| 220 | +{ | |
| 221 | + if (ar->fw.vif_num < 2) | |
| 222 | + return; | |
| 223 | + | |
| 224 | + ar->if_comb_limits[0].max = ar->fw.vif_num; | |
| 225 | + ar->if_comb_limits[0].types = if_comb_types; | |
| 226 | + | |
| 227 | + ar->if_combs[0].num_different_channels = 1; | |
| 228 | + ar->if_combs[0].max_interfaces = ar->fw.vif_num; | |
| 229 | + ar->if_combs[0].limits = ar->if_comb_limits; | |
| 230 | + ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits); | |
| 231 | + | |
| 232 | + ar->hw->wiphy->iface_combinations = ar->if_combs; | |
| 233 | + ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs); | |
| 234 | +} | |
| 235 | + | |
| 218 | 236 | static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) |
| 219 | 237 | { |
| 220 | 238 | const struct carl9170fw_otus_desc *otus_desc; |
| @@ -264,7 +282,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) · 43 unmodified lines | ||
| 264 | 282 | if (!SUPP(CARL9170FW_COMMAND_CAM)) { |
| 265 | 283 | dev_info(&ar->udev->dev, "crypto offloading is disabled " |
| 266 | 284 | "by firmware.\n"); |
| 267 | − ar->disable_offload = true; | |
| 285 | + ar->fw.disable_offload_fw = true; | |
| 268 | 286 | } |
| 269 | 287 | |
| 270 | 288 | if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM)) |
| @@ -336,25 +354,24 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) · 65 unmodified lines | ||
| 336 | 354 | if (SUPP(CARL9170FW_WLANTX_CAB)) { |
| 337 | 355 | if_comb_types |= |
| 338 | 356 | BIT(NL80211_IFTYPE_AP) | |
| 339 | − BIT(NL80211_IFTYPE_MESH_POINT) | | |
| 340 | 357 | BIT(NL80211_IFTYPE_P2P_GO); |
| 358 | + | |
| 359 | +#ifdef CONFIG_MAC80211_MESH | |
| 360 | + if_comb_types |= | |
| 361 | + BIT(NL80211_IFTYPE_MESH_POINT); | |
| 362 | +#endif /* CONFIG_MAC80211_MESH */ | |
| 341 | 363 | } |
| 342 | 364 | } |
| 343 | 365 | |
| 344 | − ar->if_comb_limits[0].max = ar->fw.vif_num; | |
| 345 | − ar->if_comb_limits[0].types = if_comb_types; | |
| 346 | − | |
| 347 | − ar->if_combs[0].num_different_channels = 1; | |
| 348 | − ar->if_combs[0].max_interfaces = ar->fw.vif_num; | |
| 349 | − ar->if_combs[0].limits = ar->if_comb_limits; | |
| 350 | − ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits); | |
| 351 | − | |
| 352 | − ar->hw->wiphy->iface_combinations = ar->if_combs; | |
| 353 | − ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs); | |
| 366 | + carl9170_fw_set_if_combinations(ar, if_comb_types); | |
| 354 | 367 | |
| 355 | 368 | ar->hw->wiphy->interface_modes |= if_comb_types; |
| 356 | 369 | |
| 357 | − ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | |
| 370 | + ar->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | |
| 371 | + | |
| 372 | + /* As IBSS Encryption is software-based, IBSS RSN is supported. */ | |
| 373 | + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | | |
| 374 | + WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_SUPPORTS_TDLS; | |
| 358 | 375 | |
| 359 | 376 | #undef SUPPORTED |
| 360 | 377 | return carl9170_fw_tx_sequence(ar); |
| @@ -156,6 +156,14 @@ struct carl9170_psm { · 155 unmodified lines | ||
| 156 | 156 | } __packed; |
| 157 | 157 | #define CARL9170_PSM_SIZE 4 |
| 158 | 158 | |
| 159 | +/* | |
| 160 | + * Note: If a bit in rx_filter is set, then it | |
| 161 | + * means that the particular frames which matches | |
| 162 | + * the condition are FILTERED/REMOVED/DISCARDED! | |
| 163 | + * (This is can be a bit confusing, especially | |
| 164 | + * because someone people think it's the exact | |
| 165 | + * opposite way, so watch out!) | |
| 166 | + */ | |
| 159 | 167 | struct carl9170_rx_filter_cmd { |
| 160 | 168 | __le32 rx_filter; |
| 161 | 169 | } __packed; |
| @@ -384,7 +384,7 @@ · 383 unmodified lines | ||
| 384 | 384 | |
| 385 | 385 | #define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xd84) |
| 386 | 386 | #define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xd88) |
| 387 | −#define AR9170_MAC_BCN_LENGTH_MAX 256 | |
| 387 | +#define AR9170_MAC_BCN_LENGTH_MAX (512 - 32) | |
| 388 | 388 | |
| 389 | 389 | #define AR9170_MAC_REG_BCN_STATUS (AR9170_MAC_REG_BASE + 0xd8c) |
| 390 | 390 | |
| @@ -358,8 +358,13 @@ static int carl9170_op_start(struct ieee80211_hw *hw) · 357 unmodified lines | ||
| 358 | 358 | ar->ps.last_action = jiffies; |
| 359 | 359 | ar->ps.last_slept = jiffies; |
| 360 | 360 | ar->erp_mode = CARL9170_ERP_AUTO; |
| 361 | − ar->rx_software_decryption = false; | |
| 362 | − ar->disable_offload = false; | |
| 361 | + | |
| 362 | + /* Set "disable hw crypto offload" whenever the module parameter | |
| 363 | + * nohwcrypt is true or if the firmware does not support it. | |
| 364 | + */ | |
| 365 | + ar->disable_offload = modparam_nohwcrypt | | |
| 366 | + ar->fw.disable_offload_fw; | |
| 367 | + ar->rx_software_decryption = ar->disable_offload; | |
| 363 | 368 | |
| 364 | 369 | for (i = 0; i < ar->hw->queues; i++) { |
| 365 | 370 | ar->queue_stop_timeout[i] = jiffies; |
| @@ -565,12 +570,28 @@ static int carl9170_init_interface(struct ar9170 *ar, · 199 unmodified lines | ||
| 565 | 570 | |
| 566 | 571 | memcpy(common->macaddr, vif->addr, ETH_ALEN); |
| 567 | 572 | |
| 568 | − if (modparam_nohwcrypt || | |
| 569 | − ((vif->type != NL80211_IFTYPE_STATION) && | |
| 570 | − (vif->type != NL80211_IFTYPE_AP))) { | |
| 571 | − ar->rx_software_decryption = true; | |
| 572 | − ar->disable_offload = true; | |
| 573 | − } | |
| 573 | + /* We have to fall back to software crypto, whenever | |
| 574 | + * the user choose to participates in an IBSS. HW | |
| 575 | + * offload for IBSS RSN is not supported by this driver. | |
| 576 | + * | |
| 577 | + * NOTE: If the previous main interface has already | |
| 578 | + * disabled hw crypto offload, we have to keep this | |
| 579 | + * previous disable_offload setting as it was. | |
| 580 | + * Altough ideally, we should notify mac80211 and tell | |
| 581 | + * it to forget about any HW crypto offload for now. | |
| 582 | + */ | |
| 583 | + ar->disable_offload |= ((vif->type != NL80211_IFTYPE_STATION) && | |
| 584 | + (vif->type != NL80211_IFTYPE_AP)); | |
| 585 | + | |
| 586 | + /* While the driver supports HW offload in a single | |
| 587 | + * P2P client configuration, it doesn't support HW | |
| 588 | + * offload in the favourit, concurrent P2P GO+CLIENT | |
| 589 | + * configuration. Hence, HW offload will always be | |
| 590 | + * disabled for P2P. | |
| 591 | + */ | |
| 592 | + ar->disable_offload |= vif->p2p; | |
| 593 | + | |
| 594 | + ar->rx_software_decryption = ar->disable_offload; | |
| 574 | 595 | |
| 575 | 596 | err = carl9170_set_operating_mode(ar); |
| 576 | 597 | return err; |
| @@ -580,7 +601,7 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, · 3 unmodified lines | ||
| 580 | 601 | struct ieee80211_vif *vif) |
| 581 | 602 | { |
| 582 | 603 | struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv; |
| 583 | − struct ieee80211_vif *main_vif; | |
| 604 | + struct ieee80211_vif *main_vif, *old_main = NULL; | |
| 584 | 605 | struct ar9170 *ar = hw->priv; |
| 585 | 606 | int vif_id = -1, err = 0; |
| 586 | 607 | |
| @@ -602,6 +623,15 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, · 15 unmodified lines | ||
| 602 | 623 | goto init; |
| 603 | 624 | } |
| 604 | 625 | |
| 626 | + /* Because the AR9170 HW's MAC doesn't provide full support for | |
| 627 | + * multiple, independent interfaces [of different operation modes]. | |
| 628 | + * We have to select ONE main interface [main mode of HW], but we | |
| 629 | + * can have multiple slaves [AKA: entry in the ACK-table]. | |
| 630 | + * | |
| 631 | + * The first (from HEAD/TOP) interface in the ar->vif_list is | |
| 632 | + * always the main intf. All following intfs in this list | |
| 633 | + * are considered to be slave intfs. | |
| 634 | + */ | |
| 605 | 635 | main_vif = carl9170_get_main_vif(ar); |
| 606 | 636 | |
| 607 | 637 | if (main_vif) { |
| @@ -610,6 +640,18 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, · 2 unmodified lines | ||
| 610 | 640 | if (vif->type == NL80211_IFTYPE_STATION) |
| 611 | 641 | break; |
| 612 | 642 | |
| 643 | + /* P2P GO [master] use-case | |
| 644 | + * Because the P2P GO station is selected dynamically | |
| 645 | + * by all participating peers of a WIFI Direct network, | |
| 646 | + * the driver has be able to change the main interface | |
| 647 | + * operating mode on the fly. | |
| 648 | + */ | |
| 649 | + if (main_vif->p2p && vif->p2p && | |
| 650 | + vif->type == NL80211_IFTYPE_AP) { | |
| 651 | + old_main = main_vif; | |
| 652 | + break; | |
| 653 | + } | |
| 654 | + | |
| 613 | 655 | err = -EBUSY; |
| 614 | 656 | rcu_read_unlock(); |
| 615 | 657 | |
| @@ -648,14 +690,41 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, · 32 unmodified lines | ||
| 648 | 690 | vif_priv->id = vif_id; |
| 649 | 691 | vif_priv->enable_beacon = false; |
| 650 | 692 | ar->vifs++; |
| 651 | − list_add_tail_rcu(&vif_priv->list, &ar->vif_list); | |
| 693 | + if (old_main) { | |
| 694 | + /* We end up in here, if the main interface is being replaced. | |
| 695 | + * Put the new main interface at the HEAD of the list and the | |
| 696 | + * previous inteface will automatically become second in line. | |
| 697 | + */ | |
| 698 | + list_add_rcu(&vif_priv->list, &ar->vif_list); | |
| 699 | + } else { | |
| 700 | + /* Add new inteface. If the list is empty, it will become the | |
| 701 | + * main inteface, otherwise it will be slave. | |
| 702 | + */ | |
| 703 | + list_add_tail_rcu(&vif_priv->list, &ar->vif_list); | |
| 704 | + } | |
| 652 | 705 | rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif); |
| 653 | 706 | |
| 654 | 707 | init: |
| 655 | − if (carl9170_get_main_vif(ar) == vif) { | |
| 708 | + main_vif = carl9170_get_main_vif(ar); | |
| 709 | + | |
| 710 | + if (main_vif == vif) { | |
| 656 | 711 | rcu_assign_pointer(ar->beacon_iter, vif_priv); |
| 657 | 712 | rcu_read_unlock(); |
| 658 | 713 | |
| 714 | + if (old_main) { | |
| 715 | + struct carl9170_vif_info *old_main_priv = | |
| 716 | + (void *) old_main->drv_priv; | |
| 717 | + /* downgrade old main intf to slave intf. | |
| 718 | + * NOTE: We are no longer under rcu_read_lock. | |
| 719 | + * But we are still holding ar->mutex, so the | |
| 720 | + * vif data [id, addr] is safe. | |
| 721 | + */ | |
| 722 | + err = carl9170_mod_virtual_mac(ar, old_main_priv->id, | |
| 723 | + old_main->addr); | |
| 724 | + if (err) | |
| 725 | + goto unlock; | |
| 726 | + } | |
| 727 | + | |
| 659 | 728 | err = carl9170_init_interface(ar, vif); |
| 660 | 729 | if (err) |
| 661 | 730 | goto unlock; |
| @@ -1112,9 +1181,7 @@ static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, · 450 unmodified lines | ||
| 1112 | 1181 | if (ar->disable_offload || !vif) |
| 1113 | 1182 | return -EOPNOTSUPP; |
| 1114 | 1183 | |
| 1115 | − /* | |
| 1116 | − * We have to fall back to software encryption, whenever | |
| 1117 | − * the user choose to participates in an IBSS or is connected | |
| 1184 | + /* Fall back to software encryption whenever the driver is connected | |
| 1118 | 1185 | * to more than one network. |
| 1119 | 1186 | * |
| 1120 | 1187 | * This is very unfortunate, because some machines cannot handle |
| @@ -1263,7 +1330,7 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw, · 142 unmodified lines | ||
| 1263 | 1330 | return 0; |
| 1264 | 1331 | } |
| 1265 | 1332 | |
| 1266 | − for (i = 0; i < CARL9170_NUM_TID; i++) | |
| 1333 | + for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) | |
| 1267 | 1334 | RCU_INIT_POINTER(sta_info->agg[i], NULL); |
| 1268 | 1335 | |
| 1269 | 1336 | sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor); |
| @@ -1287,7 +1354,7 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw, · 17 unmodified lines | ||
| 1287 | 1354 | sta_info->ht_sta = false; |
| 1288 | 1355 | |
| 1289 | 1356 | rcu_read_lock(); |
| 1290 | − for (i = 0; i < CARL9170_NUM_TID; i++) { | |
| 1357 | + for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) { | |
| 1291 | 1358 | struct carl9170_sta_tid *tid_info; |
| 1292 | 1359 | |
| 1293 | 1360 | tid_info = rcu_dereference(sta_info->agg[i]); |
| @@ -1807,10 +1874,6 @@ void *carl9170_alloc(size_t priv_size) · 513 unmodified lines | ||
| 1807 | 1874 | for (i = 0; i < ARRAY_SIZE(ar->noise); i++) |
| 1808 | 1875 | ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ |
| 1809 | 1876 | |
| 1810 | − hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | |
| 1811 | − | |
| 1812 | − /* As IBSS Encryption is software-based, IBSS RSN is supported. */ | |
| 1813 | − hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | |
| 1814 | 1877 | return ar; |
| 1815 | 1878 | |
| 1816 | 1879 | err_nomem: |
| @@ -1520,35 +1520,92 @@ void carl9170_tx_scheduler(struct ar9170 *ar) · 1519 unmodified lines | ||
| 1520 | 1520 | carl9170_tx(ar); |
| 1521 | 1521 | } |
| 1522 | 1522 | |
| 1523 | −int carl9170_update_beacon(struct ar9170 *ar, const bool submit) | |
| 1523 | +/* caller has to take rcu_read_lock */ | |
| 1524 | +static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar) | |
| 1524 | 1525 | { |
| 1525 | − struct sk_buff *skb = NULL; | |
| 1526 | 1526 | struct carl9170_vif_info *cvif; |
| 1527 | + int i = 1; | |
| 1528 | + | |
| 1529 | + /* The AR9170 hardware has no fancy beacon queue or some | |
| 1530 | + * other scheduling mechanism. So, the driver has to make | |
| 1531 | + * due by setting the two beacon timers (pretbtt and tbtt) | |
| 1532 | + * once and then swapping the beacon address in the HW's | |
| 1533 | + * register file each time the pretbtt fires. | |
| 1534 | + */ | |
| 1535 | + | |
| 1536 | + cvif = rcu_dereference(ar->beacon_iter); | |
| 1537 | + if (ar->vifs > 0 && cvif) { | |
| 1538 | + do { | |
| 1539 | + list_for_each_entry_continue_rcu(cvif, &ar->vif_list, | |
| 1540 | + list) { | |
| 1541 | + if (cvif->active && cvif->enable_beacon) | |
| 1542 | + goto out; | |
| 1543 | + } | |
| 1544 | + } while (ar->beacon_enabled && i--); | |
| 1545 | + } | |
| 1546 | + | |
| 1547 | +out: | |
| 1548 | + rcu_assign_pointer(ar->beacon_iter, cvif); | |
| 1549 | + return cvif; | |
| 1550 | +} | |
| 1551 | + | |
| 1552 | +static bool carl9170_tx_beacon_physet(struct ar9170 *ar, struct sk_buff *skb, | |
| 1553 | + u32 *ht1, u32 *plcp) | |
| 1554 | +{ | |
| 1527 | 1555 | struct ieee80211_tx_info *txinfo; |
| 1528 | 1556 | struct ieee80211_tx_rate *rate; |
| 1529 | − __le32 *data, *old = NULL; | |
| 1530 | − unsigned int plcp, power, chains; | |
| 1531 | − u32 word, ht1, off, addr, len; | |
| 1532 | − int i = 0, err = 0; | |
| 1557 | + unsigned int power, chains; | |
| 1558 | + bool ht_rate; | |
| 1533 | 1559 | |
| 1534 | − rcu_read_lock(); | |
| 1535 | − cvif = rcu_dereference(ar->beacon_iter); | |
| 1536 | −retry: | |
| 1537 | − if (ar->vifs == 0 || !cvif) | |
| 1538 | − goto out_unlock; | |
| 1560 | + txinfo = IEEE80211_SKB_CB(skb); | |
| 1561 | + rate = &txinfo->control.rates[0]; | |
| 1562 | + ht_rate = !!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS); | |
| 1563 | + carl9170_tx_rate_tpc_chains(ar, txinfo, rate, plcp, &power, &chains); | |
| 1539 | 1564 | |
| 1540 | − list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) { | |
| 1541 | − if (cvif->active && cvif->enable_beacon) | |
| 1542 | − goto found; | |
| 1565 | + *ht1 = AR9170_MAC_BCN_HT1_TX_ANT0; | |
| 1566 | + if (chains == AR9170_TX_PHY_TXCHAIN_2) | |
| 1567 | + *ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1; | |
| 1568 | + SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, *ht1, 7); | |
| 1569 | + SET_VAL(AR9170_MAC_BCN_HT1_TPC, *ht1, power); | |
| 1570 | + SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, *ht1, chains); | |
| 1571 | + | |
| 1572 | + if (ht_rate) { | |
| 1573 | + *ht1 |= AR9170_MAC_BCN_HT1_HT_EN; | |
| 1574 | + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) | |
| 1575 | + *plcp |= AR9170_MAC_BCN_HT2_SGI; | |
| 1576 | + | |
| 1577 | + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | |
| 1578 | + *ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED; | |
| 1579 | + *plcp |= AR9170_MAC_BCN_HT2_BW40; | |
| 1580 | + } else if (rate->flags & IEEE80211_TX_RC_DUP_DATA) { | |
| 1581 | + *ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP; | |
| 1582 | + *plcp |= AR9170_MAC_BCN_HT2_BW40; | |
| 1583 | + } | |
| 1584 | + | |
| 1585 | + SET_VAL(AR9170_MAC_BCN_HT2_LEN, *plcp, skb->len + FCS_LEN); | |
| 1586 | + } else { | |
| 1587 | + if (*plcp <= AR9170_TX_PHY_RATE_CCK_11M) | |
| 1588 | + *plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400; | |
| 1589 | + else | |
| 1590 | + *plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010; | |
| 1543 | 1591 | } |
| 1544 | 1592 | |
| 1545 | − if (!ar->beacon_enabled || i++) | |
| 1546 | − goto out_unlock; | |
| 1593 | + return ht_rate; | |
| 1594 | +} | |
| 1547 | 1595 | |
| 1548 | − goto retry; | |
| 1596 | +int carl9170_update_beacon(struct ar9170 *ar, const bool submit) | |
| 1597 | +{ | |
| 1598 | + struct sk_buff *skb = NULL; | |
| 1599 | + struct carl9170_vif_info *cvif; | |
| 1600 | + __le32 *data, *old = NULL; | |
| 1601 | + u32 word, ht1, plcp, off, addr, len; | |
| 1602 | + int i = 0, err = 0; | |
| 1603 | + bool ht_rate; | |
| 1549 | 1604 | |
| 1550 | −found: | |
| 1551 | − rcu_assign_pointer(ar->beacon_iter, cvif); | |
| 1605 | + rcu_read_lock(); | |
| 1606 | + cvif = carl9170_pick_beaconing_vif(ar); | |
| 1607 | + if (!cvif) | |
| 1608 | + goto out_unlock; | |
| 1552 | 1609 | |
| 1553 | 1610 | skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif), |
| 1554 | 1611 | NULL, NULL); |
| @@ -1558,7 +1615,6 @@ found: · 3 unmodified lines | ||
| 1558 | 1615 | goto err_free; |
| 1559 | 1616 | } |
| 1560 | 1617 | |
| 1561 | − txinfo = IEEE80211_SKB_CB(skb); | |
| 1562 | 1618 | spin_lock_bh(&ar->beacon_lock); |
| 1563 | 1619 | data = (__le32 *)skb->data; |
| 1564 | 1620 | if (cvif->beacon) |
| @@ -1588,43 +1644,14 @@ found: · 23 unmodified lines | ||
| 1588 | 1644 | goto err_unlock; |
| 1589 | 1645 | } |
| 1590 | 1646 | |
| 1591 | − ht1 = AR9170_MAC_BCN_HT1_TX_ANT0; | |
| 1592 | − rate = &txinfo->control.rates[0]; | |
| 1593 | − carl9170_tx_rate_tpc_chains(ar, txinfo, rate, &plcp, &power, &chains); | |
| 1594 | − if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) { | |
| 1595 | − if (plcp <= AR9170_TX_PHY_RATE_CCK_11M) | |
| 1596 | − plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400; | |
| 1597 | − else | |
| 1598 | − plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010; | |
| 1599 | − } else { | |
| 1600 | − ht1 |= AR9170_MAC_BCN_HT1_HT_EN; | |
| 1601 | − if (rate->flags & IEEE80211_TX_RC_SHORT_GI) | |
| 1602 | − plcp |= AR9170_MAC_BCN_HT2_SGI; | |
| 1603 | − | |
| 1604 | − if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | |
| 1605 | − ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED; | |
| 1606 | − plcp |= AR9170_MAC_BCN_HT2_BW40; | |
| 1607 | − } | |
| 1608 | − if (rate->flags & IEEE80211_TX_RC_DUP_DATA) { | |
| 1609 | − ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP; | |
| 1610 | − plcp |= AR9170_MAC_BCN_HT2_BW40; | |
| 1611 | − } | |
| 1612 | − | |
| 1613 | − SET_VAL(AR9170_MAC_BCN_HT2_LEN, plcp, skb->len + FCS_LEN); | |
| 1614 | − } | |
| 1615 | − | |
| 1616 | − SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, ht1, 7); | |
| 1617 | − SET_VAL(AR9170_MAC_BCN_HT1_TPC, ht1, power); | |
| 1618 | − SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, ht1, chains); | |
| 1619 | − if (chains == AR9170_TX_PHY_TXCHAIN_2) | |
| 1620 | − ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1; | |
| 1647 | + ht_rate = carl9170_tx_beacon_physet(ar, skb, &ht1, &plcp); | |
| 1621 | 1648 | |
| 1622 | 1649 | carl9170_async_regwrite_begin(ar); |
| 1623 | 1650 | carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT1, ht1); |
| 1624 | − if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) | |
| 1625 | − carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp); | |
| 1626 | − else | |
| 1651 | + if (ht_rate) | |
| 1627 | 1652 | carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT2, plcp); |
| 1653 | + else | |
| 1654 | + carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp); | |
| 1628 | 1655 | |
| 1629 | 1656 | for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { |
| 1630 | 1657 | /* |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | #ifndef __CARL9170_SHARED_VERSION_H |
| 2 | 2 | #define __CARL9170_SHARED_VERSION_H |
| 3 | 3 | #define CARL9170FW_VERSION_YEAR 12 |
| 4 | −#define CARL9170FW_VERSION_MONTH 7 | |
| 5 | −#define CARL9170FW_VERSION_DAY 7 | |
| 6 | −#define CARL9170FW_VERSION_GIT "1.9.6" | |
| 4 | +#define CARL9170FW_VERSION_MONTH 12 | |
| 5 | +#define CARL9170FW_VERSION_DAY 15 | |
| 6 | +#define CARL9170FW_VERSION_GIT "1.9.7" | |
| 7 | 7 | #endif /* __CARL9170_SHARED_VERSION_H */ |
| @@ -0,0 +1,29 @@ | ||
| 1 | +config WIL6210 | |
| 2 | + tristate "Wilocity 60g WiFi card wil6210 support" | |
| 3 | + depends on CFG80211 | |
| 4 | + depends on PCI | |
| 5 | + default n | |
| 6 | + ---help--- | |
| 7 | + This module adds support for wireless adapter based on | |
| 8 | + wil6210 chip by Wilocity. It supports operation on the | |
| 9 | + 60 GHz band, covered by the IEEE802.11ad standard. | |
| 10 | + | |
| 11 | + http://wireless.kernel.org/en/users/Drivers/wil6210 | |
| 12 | + | |
| 13 | + If you choose to build it as a module, it will be called | |
| 14 | + wil6210 | |
| 15 | + | |
| 16 | +config WIL6210_ISR_COR | |
| 17 | + bool "Use Clear-On-Read mode for ISR registers for wil6210" | |
| 18 | + depends on WIL6210 | |
| 19 | + default y | |
| 20 | + ---help--- | |
| 21 | + ISR registers on wil6210 chip may operate in either | |
| 22 | + COR (Clear-On-Read) or W1C (Write-1-to-Clear) mode. | |
| 23 | + For production code, use COR (say y); is default since | |
| 24 | + it saves extra target transaction; | |
| 25 | + For ISR debug, use W1C (say n); is allows to monitor ISR | |
| 26 | + registers with debugfs. If COR were used, ISR would | |
| 27 | + self-clear when accessed for debug purposes, it makes | |
| 28 | + such monitoring impossible. | |
| 29 | + Say y unless you debug interrupts | |
| @@ -0,0 +1,13 @@ | ||
| 1 | +obj-$(CONFIG_WIL6210) += wil6210.o | |
| 2 | + | |
| 3 | +wil6210-objs := main.o | |
| 4 | +wil6210-objs += netdev.o | |
| 5 | +wil6210-objs += cfg80211.o | |
| 6 | +wil6210-objs += pcie_bus.o | |
| 7 | +wil6210-objs += debugfs.o | |
| 8 | +wil6210-objs += wmi.o | |
| 9 | +wil6210-objs += interrupt.o | |
| 10 | +wil6210-objs += txrx.o | |
| 11 | + | |
| 12 | +subdir-ccflags-y += -Werror | |
| 13 | +subdir-ccflags-y += -D__CHECK_ENDIAN__ | |
| @@ -0,0 +1,573 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 11 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 13 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 14 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/kernel.h> | |
| 18 | +#include <linux/netdevice.h> | |
| 19 | +#include <linux/sched.h> | |
| 20 | +#include <linux/etherdevice.h> | |
| 21 | +#include <linux/wireless.h> | |
| 22 | +#include <linux/ieee80211.h> | |
| 23 | +#include <linux/slab.h> | |
| 24 | +#include <linux/version.h> | |
| 25 | +#include <net/cfg80211.h> | |
| 26 | + | |
| 27 | +#include "wil6210.h" | |
| 28 | +#include "wmi.h" | |
| 29 | + | |
| 30 | +#define CHAN60G(_channel, _flags) { \ | |
| 31 | + .band = IEEE80211_BAND_60GHZ, \ | |
| 32 | + .center_freq = 56160 + (2160 * (_channel)), \ | |
| 33 | + .hw_value = (_channel), \ | |
| 34 | + .flags = (_flags), \ | |
| 35 | + .max_antenna_gain = 0, \ | |
| 36 | + .max_power = 40, \ | |
| 37 | +} | |
| 38 | + | |
| 39 | +static struct ieee80211_channel wil_60ghz_channels[] = { | |
| 40 | + CHAN60G(1, 0), | |
| 41 | + CHAN60G(2, 0), | |
| 42 | + CHAN60G(3, 0), | |
| 43 | +/* channel 4 not supported yet */ | |
| 44 | +}; | |
| 45 | + | |
| 46 | +static struct ieee80211_supported_band wil_band_60ghz = { | |
| 47 | + .channels = wil_60ghz_channels, | |
| 48 | + .n_channels = ARRAY_SIZE(wil_60ghz_channels), | |
| 49 | + .ht_cap = { | |
| 50 | + .ht_supported = true, | |
| 51 | + .cap = 0, /* TODO */ | |
| 52 | + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, /* TODO */ | |
| 53 | + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, /* TODO */ | |
| 54 | + .mcs = { | |
| 55 | + /* MCS 1..12 - SC PHY */ | |
| 56 | + .rx_mask = {0xfe, 0x1f}, /* 1..12 */ | |
| 57 | + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, /* TODO */ | |
| 58 | + }, | |
| 59 | + }, | |
| 60 | +}; | |
| 61 | + | |
| 62 | +static const struct ieee80211_txrx_stypes | |
| 63 | +wil_mgmt_stypes[NUM_NL80211_IFTYPES] = { | |
| 64 | + [NL80211_IFTYPE_STATION] = { | |
| 65 | + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | |
| 66 | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | |
| 67 | + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | |
| 68 | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | |
| 69 | + }, | |
| 70 | + [NL80211_IFTYPE_AP] = { | |
| 71 | + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | |
| 72 | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | |
| 73 | + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | |
| 74 | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | |
| 75 | + }, | |
| 76 | + [NL80211_IFTYPE_P2P_CLIENT] = { | |
| 77 | + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | |
| 78 | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | |
| 79 | + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | |
| 80 | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | |
| 81 | + }, | |
| 82 | + [NL80211_IFTYPE_P2P_GO] = { | |
| 83 | + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | |
| 84 | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | |
| 85 | + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | |
| 86 | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | |
| 87 | + }, | |
| 88 | +}; | |
| 89 | + | |
| 90 | +static const u32 wil_cipher_suites[] = { | |
| 91 | + WLAN_CIPHER_SUITE_GCMP, | |
| 92 | +}; | |
| 93 | + | |
| 94 | +int wil_iftype_nl2wmi(enum nl80211_iftype type) | |
| 95 | +{ | |
| 96 | + static const struct { | |
| 97 | + enum nl80211_iftype nl; | |
| 98 | + enum wmi_network_type wmi; | |
| 99 | + } __nl2wmi[] = { | |
| 100 | + {NL80211_IFTYPE_ADHOC, WMI_NETTYPE_ADHOC}, | |
| 101 | + {NL80211_IFTYPE_STATION, WMI_NETTYPE_INFRA}, | |
| 102 | + {NL80211_IFTYPE_AP, WMI_NETTYPE_AP}, | |
| 103 | + {NL80211_IFTYPE_P2P_CLIENT, WMI_NETTYPE_P2P}, | |
| 104 | + {NL80211_IFTYPE_P2P_GO, WMI_NETTYPE_P2P}, | |
| 105 | + {NL80211_IFTYPE_MONITOR, WMI_NETTYPE_ADHOC}, /* FIXME */ | |
| 106 | + }; | |
| 107 | + uint i; | |
| 108 | + | |
| 109 | + for (i = 0; i < ARRAY_SIZE(__nl2wmi); i++) { | |
| 110 | + if (__nl2wmi[i].nl == type) | |
| 111 | + return __nl2wmi[i].wmi; | |
| 112 | + } | |
| 113 | + | |
| 114 | + return -EOPNOTSUPP; | |
| 115 | +} | |
| 116 | + | |
| 117 | +static int wil_cfg80211_get_station(struct wiphy *wiphy, | |
| 118 | + struct net_device *ndev, | |
| 119 | + u8 *mac, struct station_info *sinfo) | |
| 120 | +{ | |
| 121 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 122 | + int rc; | |
| 123 | + struct wmi_notify_req_cmd cmd = { | |
| 124 | + .cid = 0, | |
| 125 | + .interval_usec = 0, | |
| 126 | + }; | |
| 127 | + | |
| 128 | + if (memcmp(mac, wil->dst_addr[0], ETH_ALEN)) | |
| 129 | + return -ENOENT; | |
| 130 | + | |
| 131 | + /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */ | |
| 132 | + rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), | |
| 133 | + WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); | |
| 134 | + if (rc) | |
| 135 | + return rc; | |
| 136 | + | |
| 137 | + sinfo->generation = wil->sinfo_gen; | |
| 138 | + | |
| 139 | + sinfo->filled |= STATION_INFO_TX_BITRATE; | |
| 140 | + sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; | |
| 141 | + sinfo->txrate.mcs = wil->stats.bf_mcs; | |
| 142 | + sinfo->filled |= STATION_INFO_RX_BITRATE; | |
| 143 | + sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; | |
| 144 | + sinfo->rxrate.mcs = wil->stats.last_mcs_rx; | |
| 145 | + | |
| 146 | + if (test_bit(wil_status_fwconnected, &wil->status)) { | |
| 147 | + sinfo->filled |= STATION_INFO_SIGNAL; | |
| 148 | + sinfo->signal = 12; /* TODO: provide real value */ | |
| 149 | + } | |
| 150 | + | |
| 151 | + return 0; | |
| 152 | +} | |
| 153 | + | |
| 154 | +static int wil_cfg80211_change_iface(struct wiphy *wiphy, | |
| 155 | + struct net_device *ndev, | |
| 156 | + enum nl80211_iftype type, u32 *flags, | |
| 157 | + struct vif_params *params) | |
| 158 | +{ | |
| 159 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 160 | + struct wireless_dev *wdev = wil->wdev; | |
| 161 | + | |
| 162 | + switch (type) { | |
| 163 | + case NL80211_IFTYPE_STATION: | |
| 164 | + case NL80211_IFTYPE_AP: | |
| 165 | + case NL80211_IFTYPE_P2P_CLIENT: | |
| 166 | + case NL80211_IFTYPE_P2P_GO: | |
| 167 | + break; | |
| 168 | + case NL80211_IFTYPE_MONITOR: | |
| 169 | + if (flags) | |
| 170 | + wil->monitor_flags = *flags; | |
| 171 | + else | |
| 172 | + wil->monitor_flags = 0; | |
| 173 | + | |
| 174 | + break; | |
| 175 | + default: | |
| 176 | + return -EOPNOTSUPP; | |
| 177 | + } | |
| 178 | + | |
| 179 | + wdev->iftype = type; | |
| 180 | + | |
| 181 | + return 0; | |
| 182 | +} | |
| 183 | + | |
| 184 | +static int wil_cfg80211_scan(struct wiphy *wiphy, | |
| 185 | + struct cfg80211_scan_request *request) | |
| 186 | +{ | |
| 187 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 188 | + struct wireless_dev *wdev = wil->wdev; | |
| 189 | + struct { | |
| 190 | + struct wmi_start_scan_cmd cmd; | |
| 191 | + u16 chnl[4]; | |
| 192 | + } __packed cmd; | |
| 193 | + uint i, n; | |
| 194 | + | |
| 195 | + if (wil->scan_request) { | |
| 196 | + wil_err(wil, "Already scanning\n"); | |
| 197 | + return -EAGAIN; | |
| 198 | + } | |
| 199 | + | |
| 200 | + /* check we are client side */ | |
| 201 | + switch (wdev->iftype) { | |
| 202 | + case NL80211_IFTYPE_STATION: | |
| 203 | + case NL80211_IFTYPE_P2P_CLIENT: | |
| 204 | + break; | |
| 205 | + default: | |
| 206 | + return -EOPNOTSUPP; | |
| 207 | + | |
| 208 | + } | |
| 209 | + | |
| 210 | + /* FW don't support scan after connection attempt */ | |
| 211 | + if (test_bit(wil_status_dontscan, &wil->status)) { | |
| 212 | + wil_err(wil, "Scan after connect attempt not supported\n"); | |
| 213 | + return -EBUSY; | |
| 214 | + } | |
| 215 | + | |
| 216 | + wil->scan_request = request; | |
| 217 | + | |
| 218 | + memset(&cmd, 0, sizeof(cmd)); | |
| 219 | + cmd.cmd.num_channels = 0; | |
| 220 | + n = min(request->n_channels, 4U); | |
| 221 | + for (i = 0; i < n; i++) { | |
| 222 | + int ch = request->channels[i]->hw_value; | |
| 223 | + if (ch == 0) { | |
| 224 | + wil_err(wil, | |
| 225 | + "Scan requested for unknown frequency %dMhz\n", | |
| 226 | + request->channels[i]->center_freq); | |
| 227 | + continue; | |
| 228 | + } | |
| 229 | + /* 0-based channel indexes */ | |
| 230 | + cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1; | |
| 231 | + wil_dbg(wil, "Scan for ch %d : %d MHz\n", ch, | |
| 232 | + request->channels[i]->center_freq); | |
| 233 | + } | |
| 234 | + | |
| 235 | + return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + | |
| 236 | + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); | |
| 237 | +} | |
| 238 | + | |
| 239 | +static int wil_cfg80211_connect(struct wiphy *wiphy, | |
| 240 | + struct net_device *ndev, | |
| 241 | + struct cfg80211_connect_params *sme) | |
| 242 | +{ | |
| 243 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 244 | + struct cfg80211_bss *bss; | |
| 245 | + struct wmi_connect_cmd conn; | |
| 246 | + const u8 *ssid_eid; | |
| 247 | + const u8 *rsn_eid; | |
| 248 | + int ch; | |
| 249 | + int rc = 0; | |
| 250 | + | |
| 251 | + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, | |
| 252 | + sme->ssid, sme->ssid_len, | |
| 253 | + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | |
| 254 | + if (!bss) { | |
| 255 | + wil_err(wil, "Unable to find BSS\n"); | |
| 256 | + return -ENOENT; | |
| 257 | + } | |
| 258 | + | |
| 259 | + ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); | |
| 260 | + if (!ssid_eid) { | |
| 261 | + wil_err(wil, "No SSID\n"); | |
| 262 | + rc = -ENOENT; | |
| 263 | + goto out; | |
| 264 | + } | |
| 265 | + | |
| 266 | + rsn_eid = sme->ie ? | |
| 267 | + cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : | |
| 268 | + NULL; | |
| 269 | + if (rsn_eid) { | |
| 270 | + if (sme->ie_len > WMI_MAX_IE_LEN) { | |
| 271 | + rc = -ERANGE; | |
| 272 | + wil_err(wil, "IE too large (%td bytes)\n", | |
| 273 | + sme->ie_len); | |
| 274 | + goto out; | |
| 275 | + } | |
| 276 | + /* | |
| 277 | + * For secure assoc, send: | |
| 278 | + * (1) WMI_DELETE_CIPHER_KEY_CMD | |
| 279 | + * (2) WMI_SET_APPIE_CMD | |
| 280 | + */ | |
| 281 | + rc = wmi_del_cipher_key(wil, 0, bss->bssid); | |
| 282 | + if (rc) { | |
| 283 | + wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n"); | |
| 284 | + goto out; | |
| 285 | + } | |
| 286 | + /* WMI_SET_APPIE_CMD */ | |
| 287 | + rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); | |
| 288 | + if (rc) { | |
| 289 | + wil_err(wil, "WMI_SET_APPIE_CMD failed\n"); | |
| 290 | + goto out; | |
| 291 | + } | |
| 292 | + } | |
| 293 | + | |
| 294 | + /* WMI_CONNECT_CMD */ | |
| 295 | + memset(&conn, 0, sizeof(conn)); | |
| 296 | + switch (bss->capability & 0x03) { | |
| 297 | + case WLAN_CAPABILITY_DMG_TYPE_AP: | |
| 298 | + conn.network_type = WMI_NETTYPE_INFRA; | |
| 299 | + break; | |
| 300 | + case WLAN_CAPABILITY_DMG_TYPE_PBSS: | |
| 301 | + conn.network_type = WMI_NETTYPE_P2P; | |
| 302 | + break; | |
| 303 | + default: | |
| 304 | + wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n", | |
| 305 | + bss->capability); | |
| 306 | + goto out; | |
| 307 | + } | |
| 308 | + if (rsn_eid) { | |
| 309 | + conn.dot11_auth_mode = WMI_AUTH11_SHARED; | |
| 310 | + conn.auth_mode = WMI_AUTH_WPA2_PSK; | |
| 311 | + conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP; | |
| 312 | + conn.pairwise_crypto_len = 16; | |
| 313 | + } else { | |
| 314 | + conn.dot11_auth_mode = WMI_AUTH11_OPEN; | |
| 315 | + conn.auth_mode = WMI_AUTH_NONE; | |
| 316 | + } | |
| 317 | + | |
| 318 | + conn.ssid_len = min_t(u8, ssid_eid[1], 32); | |
| 319 | + memcpy(conn.ssid, ssid_eid+2, conn.ssid_len); | |
| 320 | + | |
| 321 | + ch = bss->channel->hw_value; | |
| 322 | + if (ch == 0) { | |
| 323 | + wil_err(wil, "BSS at unknown frequency %dMhz\n", | |
| 324 | + bss->channel->center_freq); | |
| 325 | + rc = -EOPNOTSUPP; | |
| 326 | + goto out; | |
| 327 | + } | |
| 328 | + conn.channel = ch - 1; | |
| 329 | + | |
| 330 | + memcpy(conn.bssid, bss->bssid, 6); | |
| 331 | + memcpy(conn.dst_mac, bss->bssid, 6); | |
| 332 | + /* | |
| 333 | + * FW don't support scan after connection attempt | |
| 334 | + */ | |
| 335 | + set_bit(wil_status_dontscan, &wil->status); | |
| 336 | + | |
| 337 | + rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); | |
| 338 | + if (rc == 0) { | |
| 339 | + /* Connect can take lots of time */ | |
| 340 | + mod_timer(&wil->connect_timer, | |
| 341 | + jiffies + msecs_to_jiffies(2000)); | |
| 342 | + } | |
| 343 | + | |
| 344 | + out: | |
| 345 | + cfg80211_put_bss(bss); | |
| 346 | + | |
| 347 | + return rc; | |
| 348 | +} | |
| 349 | + | |
| 350 | +static int wil_cfg80211_disconnect(struct wiphy *wiphy, | |
| 351 | + struct net_device *ndev, | |
| 352 | + u16 reason_code) | |
| 353 | +{ | |
| 354 | + int rc; | |
| 355 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 356 | + | |
| 357 | + rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); | |
| 358 | + | |
| 359 | + return rc; | |
| 360 | +} | |
| 361 | + | |
| 362 | +static int wil_cfg80211_set_channel(struct wiphy *wiphy, | |
| 363 | + struct cfg80211_chan_def *chandef) | |
| 364 | +{ | |
| 365 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 366 | + struct wireless_dev *wdev = wil->wdev; | |
| 367 | + | |
| 368 | + wdev->preset_chandef = *chandef; | |
| 369 | + | |
| 370 | + return 0; | |
| 371 | +} | |
| 372 | + | |
| 373 | +static int wil_cfg80211_add_key(struct wiphy *wiphy, | |
| 374 | + struct net_device *ndev, | |
| 375 | + u8 key_index, bool pairwise, | |
| 376 | + const u8 *mac_addr, | |
| 377 | + struct key_params *params) | |
| 378 | +{ | |
| 379 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 380 | + | |
| 381 | + /* group key is not used */ | |
| 382 | + if (!pairwise) | |
| 383 | + return 0; | |
| 384 | + | |
| 385 | + return wmi_add_cipher_key(wil, key_index, mac_addr, | |
| 386 | + params->key_len, params->key); | |
| 387 | +} | |
| 388 | + | |
| 389 | +static int wil_cfg80211_del_key(struct wiphy *wiphy, | |
| 390 | + struct net_device *ndev, | |
| 391 | + u8 key_index, bool pairwise, | |
| 392 | + const u8 *mac_addr) | |
| 393 | +{ | |
| 394 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 395 | + | |
| 396 | + /* group key is not used */ | |
| 397 | + if (!pairwise) | |
| 398 | + return 0; | |
| 399 | + | |
| 400 | + return wmi_del_cipher_key(wil, key_index, mac_addr); | |
| 401 | +} | |
| 402 | + | |
| 403 | +/* Need to be present or wiphy_new() will WARN */ | |
| 404 | +static int wil_cfg80211_set_default_key(struct wiphy *wiphy, | |
| 405 | + struct net_device *ndev, | |
| 406 | + u8 key_index, bool unicast, | |
| 407 | + bool multicast) | |
| 408 | +{ | |
| 409 | + return 0; | |
| 410 | +} | |
| 411 | + | |
| 412 | +static int wil_cfg80211_start_ap(struct wiphy *wiphy, | |
| 413 | + struct net_device *ndev, | |
| 414 | + struct cfg80211_ap_settings *info) | |
| 415 | +{ | |
| 416 | + int rc = 0; | |
| 417 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 418 | + struct wireless_dev *wdev = ndev->ieee80211_ptr; | |
| 419 | + struct ieee80211_channel *channel = info->chandef.chan; | |
| 420 | + struct cfg80211_beacon_data *bcon = &info->beacon; | |
| 421 | + u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); | |
| 422 | + | |
| 423 | + if (!channel) { | |
| 424 | + wil_err(wil, "AP: No channel???\n"); | |
| 425 | + return -EINVAL; | |
| 426 | + } | |
| 427 | + | |
| 428 | + wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, | |
| 429 | + channel->center_freq, info->privacy ? "secure" : "open"); | |
| 430 | + print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, | |
| 431 | + info->ssid, info->ssid_len); | |
| 432 | + | |
| 433 | + rc = wil_reset(wil); | |
| 434 | + if (rc) | |
| 435 | + return rc; | |
| 436 | + | |
| 437 | + rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); | |
| 438 | + if (rc) | |
| 439 | + return rc; | |
| 440 | + | |
| 441 | + rc = wmi_set_channel(wil, channel->hw_value); | |
| 442 | + if (rc) | |
| 443 | + return rc; | |
| 444 | + | |
| 445 | + /* MAC address - pre-requisite for other commands */ | |
| 446 | + wmi_set_mac_address(wil, ndev->dev_addr); | |
| 447 | + | |
| 448 | + /* IE's */ | |
| 449 | + /* bcon 'head IE's are not relevant for 60g band */ | |
| 450 | + wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, | |
| 451 | + bcon->beacon_ies); | |
| 452 | + wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, | |
| 453 | + bcon->proberesp_ies); | |
| 454 | + wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, | |
| 455 | + bcon->assocresp_ies); | |
| 456 | + | |
| 457 | + wil->secure_pcp = info->privacy; | |
| 458 | + | |
| 459 | + rc = wmi_set_bcon(wil, info->beacon_interval, wmi_nettype); | |
| 460 | + if (rc) | |
| 461 | + return rc; | |
| 462 | + | |
| 463 | + /* Rx VRING. After MAC and beacon */ | |
| 464 | + rc = wil_rx_init(wil); | |
| 465 | + | |
| 466 | + netif_carrier_on(ndev); | |
| 467 | + | |
| 468 | + return rc; | |
| 469 | +} | |
| 470 | + | |
| 471 | +static int wil_cfg80211_stop_ap(struct wiphy *wiphy, | |
| 472 | + struct net_device *ndev) | |
| 473 | +{ | |
| 474 | + int rc = 0; | |
| 475 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 476 | + struct wireless_dev *wdev = ndev->ieee80211_ptr; | |
| 477 | + u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); | |
| 478 | + | |
| 479 | + /* To stop beaconing, set BI to 0 */ | |
| 480 | + rc = wmi_set_bcon(wil, 0, wmi_nettype); | |
| 481 | + | |
| 482 | + return rc; | |
| 483 | +} | |
| 484 | + | |
| 485 | +static struct cfg80211_ops wil_cfg80211_ops = { | |
| 486 | + .scan = wil_cfg80211_scan, | |
| 487 | + .connect = wil_cfg80211_connect, | |
| 488 | + .disconnect = wil_cfg80211_disconnect, | |
| 489 | + .change_virtual_intf = wil_cfg80211_change_iface, | |
| 490 | + .get_station = wil_cfg80211_get_station, | |
| 491 | + .set_monitor_channel = wil_cfg80211_set_channel, | |
| 492 | + .add_key = wil_cfg80211_add_key, | |
| 493 | + .del_key = wil_cfg80211_del_key, | |
| 494 | + .set_default_key = wil_cfg80211_set_default_key, | |
| 495 | + /* AP mode */ | |
| 496 | + .start_ap = wil_cfg80211_start_ap, | |
| 497 | + .stop_ap = wil_cfg80211_stop_ap, | |
| 498 | +}; | |
| 499 | + | |
| 500 | +static void wil_wiphy_init(struct wiphy *wiphy) | |
| 501 | +{ | |
| 502 | + /* TODO: set real value */ | |
| 503 | + wiphy->max_scan_ssids = 10; | |
| 504 | + wiphy->max_num_pmkids = 0 /* TODO: */; | |
| 505 | + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | |
| 506 | + BIT(NL80211_IFTYPE_AP) | | |
| 507 | + BIT(NL80211_IFTYPE_MONITOR); | |
| 508 | + /* TODO: enable P2P when integrated with supplicant: | |
| 509 | + * BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | |
| 510 | + */ | |
| 511 | + wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | | |
| 512 | + WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | |
| 513 | + dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n", | |
| 514 | + __func__, wiphy->flags); | |
| 515 | + wiphy->probe_resp_offload = | |
| 516 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | | |
| 517 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | | |
| 518 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; | |
| 519 | + | |
| 520 | + wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz; | |
| 521 | + | |
| 522 | + /* TODO: figure this out */ | |
| 523 | + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | |
| 524 | + | |
| 525 | + wiphy->cipher_suites = wil_cipher_suites; | |
| 526 | + wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); | |
| 527 | + wiphy->mgmt_stypes = wil_mgmt_stypes; | |
| 528 | +} | |
| 529 | + | |
| 530 | +struct wireless_dev *wil_cfg80211_init(struct device *dev) | |
| 531 | +{ | |
| 532 | + int rc = 0; | |
| 533 | + struct wireless_dev *wdev; | |
| 534 | + | |
| 535 | + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | |
| 536 | + if (!wdev) | |
| 537 | + return ERR_PTR(-ENOMEM); | |
| 538 | + | |
| 539 | + wdev->wiphy = wiphy_new(&wil_cfg80211_ops, | |
| 540 | + sizeof(struct wil6210_priv)); | |
| 541 | + if (!wdev->wiphy) { | |
| 542 | + rc = -ENOMEM; | |
| 543 | + goto out; | |
| 544 | + } | |
| 545 | + | |
| 546 | + set_wiphy_dev(wdev->wiphy, dev); | |
| 547 | + wil_wiphy_init(wdev->wiphy); | |
| 548 | + | |
| 549 | + rc = wiphy_register(wdev->wiphy); | |
| 550 | + if (rc < 0) | |
| 551 | + goto out_failed_reg; | |
| 552 | + | |
| 553 | + return wdev; | |
| 554 | + | |
| 555 | +out_failed_reg: | |
| 556 | + wiphy_free(wdev->wiphy); | |
| 557 | +out: | |
| 558 | + kfree(wdev); | |
| 559 | + | |
| 560 | + return ERR_PTR(rc); | |
| 561 | +} | |
| 562 | + | |
| 563 | +void wil_wdev_free(struct wil6210_priv *wil) | |
| 564 | +{ | |
| 565 | + struct wireless_dev *wdev = wil_to_wdev(wil); | |
| 566 | + | |
| 567 | + if (!wdev) | |
| 568 | + return; | |
| 569 | + | |
| 570 | + wiphy_unregister(wdev->wiphy); | |
| 571 | + wiphy_free(wdev->wiphy); | |
| 572 | + kfree(wdev); | |
| 573 | +} | |
| @@ -0,0 +1,30 @@ | ||
| 1 | +#ifndef WIL_DBG_HEXDUMP_H_ | |
| 2 | +#define WIL_DBG_HEXDUMP_H_ | |
| 3 | + | |
| 4 | +#if defined(CONFIG_DYNAMIC_DEBUG) | |
| 5 | +#define wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \ | |
| 6 | + groupsize, buf, len, ascii) \ | |
| 7 | +do { \ | |
| 8 | + DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, \ | |
| 9 | + __builtin_constant_p(prefix_str) ? prefix_str : "hexdump");\ | |
| 10 | + if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \ | |
| 11 | + print_hex_dump(KERN_DEBUG, prefix_str, \ | |
| 12 | + prefix_type, rowsize, groupsize, \ | |
| 13 | + buf, len, ascii); \ | |
| 14 | +} while (0) | |
| 15 | + | |
| 16 | +#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ | |
| 17 | + groupsize, buf, len, ascii) \ | |
| 18 | + wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \ | |
| 19 | + groupsize, buf, len, ascii) | |
| 20 | + | |
| 21 | +#define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ | |
| 22 | + wil_dynamic_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true) | |
| 23 | +#else /* defined(CONFIG_DYNAMIC_DEBUG) */ | |
| 24 | +#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ | |
| 25 | + groupsize, buf, len, ascii) \ | |
| 26 | + print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ | |
| 27 | + groupsize, buf, len, ascii) | |
| 28 | +#endif /* defined(CONFIG_DYNAMIC_DEBUG) */ | |
| 29 | + | |
| 30 | +#endif /* WIL_DBG_HEXDUMP_H_ */ | |
| @@ -0,0 +1,603 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 11 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 13 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 14 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/module.h> | |
| 18 | +#include <linux/debugfs.h> | |
| 19 | +#include <linux/seq_file.h> | |
| 20 | +#include <linux/pci.h> | |
| 21 | +#include <linux/rtnetlink.h> | |
| 22 | + | |
| 23 | +#include "wil6210.h" | |
| 24 | +#include "txrx.h" | |
| 25 | + | |
| 26 | +/* Nasty hack. Better have per device instances */ | |
| 27 | +static u32 mem_addr; | |
| 28 | +static u32 dbg_txdesc_index; | |
| 29 | + | |
| 30 | +static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, | |
| 31 | + const char *name, struct vring *vring) | |
| 32 | +{ | |
| 33 | + void __iomem *x = wmi_addr(wil, vring->hwtail); | |
| 34 | + | |
| 35 | + seq_printf(s, "VRING %s = {\n", name); | |
| 36 | + seq_printf(s, " pa = 0x%016llx\n", (unsigned long long)vring->pa); | |
| 37 | + seq_printf(s, " va = 0x%p\n", vring->va); | |
| 38 | + seq_printf(s, " size = %d\n", vring->size); | |
| 39 | + seq_printf(s, " swtail = %d\n", vring->swtail); | |
| 40 | + seq_printf(s, " swhead = %d\n", vring->swhead); | |
| 41 | + seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail); | |
| 42 | + if (x) | |
| 43 | + seq_printf(s, "0x%08x\n", ioread32(x)); | |
| 44 | + else | |
| 45 | + seq_printf(s, "???\n"); | |
| 46 | + | |
| 47 | + if (vring->va && (vring->size < 1025)) { | |
| 48 | + uint i; | |
| 49 | + for (i = 0; i < vring->size; i++) { | |
| 50 | + volatile struct vring_tx_desc *d = &vring->va[i].tx; | |
| 51 | + if ((i % 64) == 0 && (i != 0)) | |
| 52 | + seq_printf(s, "\n"); | |
| 53 | + seq_printf(s, "%s", (d->dma.status & BIT(0)) ? | |
| 54 | + "S" : (vring->ctx[i] ? "H" : "h")); | |
| 55 | + } | |
| 56 | + seq_printf(s, "\n"); | |
| 57 | + } | |
| 58 | + seq_printf(s, "}\n"); | |
| 59 | +} | |
| 60 | + | |
| 61 | +static int wil_vring_debugfs_show(struct seq_file *s, void *data) | |
| 62 | +{ | |
| 63 | + uint i; | |
| 64 | + struct wil6210_priv *wil = s->private; | |
| 65 | + | |
| 66 | + wil_print_vring(s, wil, "rx", &wil->vring_rx); | |
| 67 | + | |
| 68 | + for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { | |
| 69 | + struct vring *vring = &(wil->vring_tx[i]); | |
| 70 | + if (vring->va) { | |
| 71 | + char name[10]; | |
| 72 | + snprintf(name, sizeof(name), "tx_%2d", i); | |
| 73 | + wil_print_vring(s, wil, name, vring); | |
| 74 | + } | |
| 75 | + } | |
| 76 | + | |
| 77 | + return 0; | |
| 78 | +} | |
| 79 | + | |
| 80 | +static int wil_vring_seq_open(struct inode *inode, struct file *file) | |
| 81 | +{ | |
| 82 | + return single_open(file, wil_vring_debugfs_show, inode->i_private); | |
| 83 | +} | |
| 84 | + | |
| 85 | +static const struct file_operations fops_vring = { | |
| 86 | + .open = wil_vring_seq_open, | |
| 87 | + .release = single_release, | |
| 88 | + .read = seq_read, | |
| 89 | + .llseek = seq_lseek, | |
| 90 | +}; | |
| 91 | + | |
| 92 | +static void wil_print_ring(struct seq_file *s, const char *prefix, | |
| 93 | + void __iomem *off) | |
| 94 | +{ | |
| 95 | + struct wil6210_priv *wil = s->private; | |
| 96 | + struct wil6210_mbox_ring r; | |
| 97 | + int rsize; | |
| 98 | + uint i; | |
| 99 | + | |
| 100 | + wil_memcpy_fromio_32(&r, off, sizeof(r)); | |
| 101 | + wil_mbox_ring_le2cpus(&r); | |
| 102 | + /* | |
| 103 | + * we just read memory block from NIC. This memory may be | |
| 104 | + * garbage. Check validity before using it. | |
| 105 | + */ | |
| 106 | + rsize = r.size / sizeof(struct wil6210_mbox_ring_desc); | |
| 107 | + | |
| 108 | + seq_printf(s, "ring %s = {\n", prefix); | |
| 109 | + seq_printf(s, " base = 0x%08x\n", r.base); | |
| 110 | + seq_printf(s, " size = 0x%04x bytes -> %d entries\n", r.size, rsize); | |
| 111 | + seq_printf(s, " tail = 0x%08x\n", r.tail); | |
| 112 | + seq_printf(s, " head = 0x%08x\n", r.head); | |
| 113 | + seq_printf(s, " entry size = %d\n", r.entry_size); | |
| 114 | + | |
| 115 | + if (r.size % sizeof(struct wil6210_mbox_ring_desc)) { | |
| 116 | + seq_printf(s, " ??? size is not multiple of %zd, garbage?\n", | |
| 117 | + sizeof(struct wil6210_mbox_ring_desc)); | |
| 118 | + goto out; | |
| 119 | + } | |
| 120 | + | |
| 121 | + if (!wmi_addr(wil, r.base) || | |
| 122 | + !wmi_addr(wil, r.tail) || | |
| 123 | + !wmi_addr(wil, r.head)) { | |
| 124 | + seq_printf(s, " ??? pointers are garbage?\n"); | |
| 125 | + goto out; | |
| 126 | + } | |
| 127 | + | |
| 128 | + for (i = 0; i < rsize; i++) { | |
| 129 | + struct wil6210_mbox_ring_desc d; | |
| 130 | + struct wil6210_mbox_hdr hdr; | |
| 131 | + size_t delta = i * sizeof(d); | |
| 132 | + void __iomem *x = wil->csr + HOSTADDR(r.base) + delta; | |
| 133 | + | |
| 134 | + wil_memcpy_fromio_32(&d, x, sizeof(d)); | |
| 135 | + | |
| 136 | + seq_printf(s, " [%2x] %s %s%s 0x%08x", i, | |
| 137 | + d.sync ? "F" : "E", | |
| 138 | + (r.tail - r.base == delta) ? "t" : " ", | |
| 139 | + (r.head - r.base == delta) ? "h" : " ", | |
| 140 | + le32_to_cpu(d.addr)); | |
| 141 | + if (0 == wmi_read_hdr(wil, d.addr, &hdr)) { | |
| 142 | + u16 len = le16_to_cpu(hdr.len); | |
| 143 | + seq_printf(s, " -> %04x %04x %04x %02x\n", | |
| 144 | + le16_to_cpu(hdr.seq), len, | |
| 145 | + le16_to_cpu(hdr.type), hdr.flags); | |
| 146 | + if (len <= MAX_MBOXITEM_SIZE) { | |
| 147 | + int n = 0; | |
| 148 | + unsigned char printbuf[16 * 3 + 2]; | |
| 149 | + unsigned char databuf[MAX_MBOXITEM_SIZE]; | |
| 150 | + void __iomem *src = wmi_buffer(wil, d.addr) + | |
| 151 | + sizeof(struct wil6210_mbox_hdr); | |
| 152 | + /* | |
| 153 | + * No need to check @src for validity - | |
| 154 | + * we already validated @d.addr while | |
| 155 | + * reading header | |
| 156 | + */ | |
| 157 | + wil_memcpy_fromio_32(databuf, src, len); | |
| 158 | + while (n < len) { | |
| 159 | + int l = min(len - n, 16); | |
| 160 | + hex_dump_to_buffer(databuf + n, l, | |
| 161 | + 16, 1, printbuf, | |
| 162 | + sizeof(printbuf), | |
| 163 | + false); | |
| 164 | + seq_printf(s, " : %s\n", printbuf); | |
| 165 | + n += l; | |
| 166 | + } | |
| 167 | + } | |
| 168 | + } else { | |
| 169 | + seq_printf(s, "\n"); | |
| 170 | + } | |
| 171 | + } | |
| 172 | + out: | |
| 173 | + seq_printf(s, "}\n"); | |
| 174 | +} | |
| 175 | + | |
| 176 | +static int wil_mbox_debugfs_show(struct seq_file *s, void *data) | |
| 177 | +{ | |
| 178 | + struct wil6210_priv *wil = s->private; | |
| 179 | + | |
| 180 | + wil_print_ring(s, "tx", wil->csr + HOST_MBOX + | |
| 181 | + offsetof(struct wil6210_mbox_ctl, tx)); | |
| 182 | + wil_print_ring(s, "rx", wil->csr + HOST_MBOX + | |
| 183 | + offsetof(struct wil6210_mbox_ctl, rx)); | |
| 184 | + | |
| 185 | + return 0; | |
| 186 | +} | |
| 187 | + | |
| 188 | +static int wil_mbox_seq_open(struct inode *inode, struct file *file) | |
| 189 | +{ | |
| 190 | + return single_open(file, wil_mbox_debugfs_show, inode->i_private); | |
| 191 | +} | |
| 192 | + | |
| 193 | +static const struct file_operations fops_mbox = { | |
| 194 | + .open = wil_mbox_seq_open, | |
| 195 | + .release = single_release, | |
| 196 | + .read = seq_read, | |
| 197 | + .llseek = seq_lseek, | |
| 198 | +}; | |
| 199 | + | |
| 200 | +static int wil_debugfs_iomem_x32_set(void *data, u64 val) | |
| 201 | +{ | |
| 202 | + iowrite32(val, (void __iomem *)data); | |
| 203 | + wmb(); /* make sure write propagated to HW */ | |
| 204 | + | |
| 205 | + return 0; | |
| 206 | +} | |
| 207 | + | |
| 208 | +static int wil_debugfs_iomem_x32_get(void *data, u64 *val) | |
| 209 | +{ | |
| 210 | + *val = ioread32((void __iomem *)data); | |
| 211 | + | |
| 212 | + return 0; | |
| 213 | +} | |
| 214 | + | |
| 215 | +DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get, | |
| 216 | + wil_debugfs_iomem_x32_set, "0x%08llx\n"); | |
| 217 | + | |
| 218 | +static struct dentry *wil_debugfs_create_iomem_x32(const char *name, | |
| 219 | + mode_t mode, | |
| 220 | + struct dentry *parent, | |
| 221 | + void __iomem *value) | |
| 222 | +{ | |
| 223 | + return debugfs_create_file(name, mode, parent, (void * __force)value, | |
| 224 | + &fops_iomem_x32); | |
| 225 | +} | |
| 226 | + | |
| 227 | +static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, | |
| 228 | + const char *name, | |
| 229 | + struct dentry *parent, u32 off) | |
| 230 | +{ | |
| 231 | + struct dentry *d = debugfs_create_dir(name, parent); | |
| 232 | + | |
| 233 | + if (IS_ERR_OR_NULL(d)) | |
| 234 | + return -ENODEV; | |
| 235 | + | |
| 236 | + wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d, | |
| 237 | + wil->csr + off); | |
| 238 | + wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d, | |
| 239 | + wil->csr + off + 4); | |
| 240 | + wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d, | |
| 241 | + wil->csr + off + 8); | |
| 242 | + wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d, | |
| 243 | + wil->csr + off + 12); | |
| 244 | + wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d, | |
| 245 | + wil->csr + off + 16); | |
| 246 | + wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d, | |
| 247 | + wil->csr + off + 20); | |
| 248 | + wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d, | |
| 249 | + wil->csr + off + 24); | |
| 250 | + | |
| 251 | + return 0; | |
| 252 | +} | |
| 253 | + | |
| 254 | +static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, | |
| 255 | + struct dentry *parent) | |
| 256 | +{ | |
| 257 | + struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent); | |
| 258 | + | |
| 259 | + if (IS_ERR_OR_NULL(d)) | |
| 260 | + return -ENODEV; | |
| 261 | + | |
| 262 | + wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr + | |
| 263 | + HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); | |
| 264 | + wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr + | |
| 265 | + HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); | |
| 266 | + wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr + | |
| 267 | + HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW)); | |
| 268 | + | |
| 269 | + return 0; | |
| 270 | +} | |
| 271 | + | |
| 272 | +static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, | |
| 273 | + struct dentry *parent) | |
| 274 | +{ | |
| 275 | + struct dentry *d = debugfs_create_dir("ITR_CNT", parent); | |
| 276 | + | |
| 277 | + if (IS_ERR_OR_NULL(d)) | |
| 278 | + return -ENODEV; | |
| 279 | + | |
| 280 | + wil_debugfs_create_iomem_x32("TRSH", S_IRUGO, d, wil->csr + | |
| 281 | + HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); | |
| 282 | + wil_debugfs_create_iomem_x32("DATA", S_IRUGO, d, wil->csr + | |
| 283 | + HOSTADDR(RGF_DMA_ITR_CNT_DATA)); | |
| 284 | + wil_debugfs_create_iomem_x32("CTL", S_IRUGO, d, wil->csr + | |
| 285 | + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); | |
| 286 | + | |
| 287 | + return 0; | |
| 288 | +} | |
| 289 | + | |
| 290 | +static int wil_memread_debugfs_show(struct seq_file *s, void *data) | |
| 291 | +{ | |
| 292 | + struct wil6210_priv *wil = s->private; | |
| 293 | + void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr)); | |
| 294 | + | |
| 295 | + if (a) | |
| 296 | + seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a)); | |
| 297 | + else | |
| 298 | + seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); | |
| 299 | + | |
| 300 | + return 0; | |
| 301 | +} | |
| 302 | + | |
| 303 | +static int wil_memread_seq_open(struct inode *inode, struct file *file) | |
| 304 | +{ | |
| 305 | + return single_open(file, wil_memread_debugfs_show, inode->i_private); | |
| 306 | +} | |
| 307 | + | |
| 308 | +static const struct file_operations fops_memread = { | |
| 309 | + .open = wil_memread_seq_open, | |
| 310 | + .release = single_release, | |
| 311 | + .read = seq_read, | |
| 312 | + .llseek = seq_lseek, | |
| 313 | +}; | |
| 314 | + | |
| 315 | +static int wil_default_open(struct inode *inode, struct file *file) | |
| 316 | +{ | |
| 317 | + if (inode->i_private) | |
| 318 | + file->private_data = inode->i_private; | |
| 319 | + | |
| 320 | + return 0; | |
| 321 | +} | |
| 322 | + | |
| 323 | +static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, | |
| 324 | + size_t count, loff_t *ppos) | |
| 325 | +{ | |
| 326 | + enum { max_count = 4096 }; | |
| 327 | + struct debugfs_blob_wrapper *blob = file->private_data; | |
| 328 | + loff_t pos = *ppos; | |
| 329 | + size_t available = blob->size; | |
| 330 | + void *buf; | |
| 331 | + size_t ret; | |
| 332 | + | |
| 333 | + if (pos < 0) | |
| 334 | + return -EINVAL; | |
| 335 | + | |
| 336 | + if (pos >= available || !count) | |
| 337 | + return 0; | |
| 338 | + | |
| 339 | + if (count > available - pos) | |
| 340 | + count = available - pos; | |
| 341 | + if (count > max_count) | |
| 342 | + count = max_count; | |
| 343 | + | |
| 344 | + buf = kmalloc(count, GFP_KERNEL); | |
| 345 | + if (!buf) | |
| 346 | + return -ENOMEM; | |
| 347 | + | |
| 348 | + wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data + | |
| 349 | + pos, count); | |
| 350 | + | |
| 351 | + ret = copy_to_user(user_buf, buf, count); | |
| 352 | + kfree(buf); | |
| 353 | + if (ret == count) | |
| 354 | + return -EFAULT; | |
| 355 | + | |
| 356 | + count -= ret; | |
| 357 | + *ppos = pos + count; | |
| 358 | + | |
| 359 | + return count; | |
| 360 | +} | |
| 361 | + | |
| 362 | +static const struct file_operations fops_ioblob = { | |
| 363 | + .read = wil_read_file_ioblob, | |
| 364 | + .open = wil_default_open, | |
| 365 | + .llseek = default_llseek, | |
| 366 | +}; | |
| 367 | + | |
| 368 | +static | |
| 369 | +struct dentry *wil_debugfs_create_ioblob(const char *name, | |
| 370 | + mode_t mode, | |
| 371 | + struct dentry *parent, | |
| 372 | + struct debugfs_blob_wrapper *blob) | |
| 373 | +{ | |
| 374 | + return debugfs_create_file(name, mode, parent, blob, &fops_ioblob); | |
| 375 | +} | |
| 376 | +/*---reset---*/ | |
| 377 | +static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, | |
| 378 | + size_t len, loff_t *ppos) | |
| 379 | +{ | |
| 380 | + struct wil6210_priv *wil = file->private_data; | |
| 381 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 382 | + | |
| 383 | + /** | |
| 384 | + * BUG: | |
| 385 | + * this code does NOT sync device state with the rest of system | |
| 386 | + * use with care, debug only!!! | |
| 387 | + */ | |
| 388 | + rtnl_lock(); | |
| 389 | + dev_close(ndev); | |
| 390 | + ndev->flags &= ~IFF_UP; | |
| 391 | + rtnl_unlock(); | |
| 392 | + wil_reset(wil); | |
| 393 | + | |
| 394 | + return len; | |
| 395 | +} | |
| 396 | + | |
| 397 | +static const struct file_operations fops_reset = { | |
| 398 | + .write = wil_write_file_reset, | |
| 399 | + .open = wil_default_open, | |
| 400 | +}; | |
| 401 | +/*---------Tx descriptor------------*/ | |
| 402 | + | |
| 403 | +static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) | |
| 404 | +{ | |
| 405 | + struct wil6210_priv *wil = s->private; | |
| 406 | + struct vring *vring = &(wil->vring_tx[0]); | |
| 407 | + | |
| 408 | + if (!vring->va) { | |
| 409 | + seq_printf(s, "No Tx VRING\n"); | |
| 410 | + return 0; | |
| 411 | + } | |
| 412 | + | |
| 413 | + if (dbg_txdesc_index < vring->size) { | |
| 414 | + volatile struct vring_tx_desc *d = | |
| 415 | + &(vring->va[dbg_txdesc_index].tx); | |
| 416 | + volatile u32 *u = (volatile u32 *)d; | |
| 417 | + struct sk_buff *skb = vring->ctx[dbg_txdesc_index]; | |
| 418 | + | |
| 419 | + seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); | |
| 420 | + seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", | |
| 421 | + u[0], u[1], u[2], u[3]); | |
| 422 | + seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", | |
| 423 | + u[4], u[5], u[6], u[7]); | |
| 424 | + seq_printf(s, " SKB = %p\n", skb); | |
| 425 | + | |
| 426 | + if (skb) { | |
| 427 | + unsigned char printbuf[16 * 3 + 2]; | |
| 428 | + int i = 0; | |
| 429 | + int len = skb_headlen(skb); | |
| 430 | + void *p = skb->data; | |
| 431 | + | |
| 432 | + seq_printf(s, " len = %d\n", len); | |
| 433 | + | |
| 434 | + while (i < len) { | |
| 435 | + int l = min(len - i, 16); | |
| 436 | + hex_dump_to_buffer(p + i, l, 16, 1, printbuf, | |
| 437 | + sizeof(printbuf), false); | |
| 438 | + seq_printf(s, " : %s\n", printbuf); | |
| 439 | + i += l; | |
| 440 | + } | |
| 441 | + } | |
| 442 | + seq_printf(s, "}\n"); | |
| 443 | + } else { | |
| 444 | + seq_printf(s, "TxDesc index (%d) >= size (%d)\n", | |
| 445 | + dbg_txdesc_index, vring->size); | |
| 446 | + } | |
| 447 | + | |
| 448 | + return 0; | |
| 449 | +} | |
| 450 | + | |
| 451 | +static int wil_txdesc_seq_open(struct inode *inode, struct file *file) | |
| 452 | +{ | |
| 453 | + return single_open(file, wil_txdesc_debugfs_show, inode->i_private); | |
| 454 | +} | |
| 455 | + | |
| 456 | +static const struct file_operations fops_txdesc = { | |
| 457 | + .open = wil_txdesc_seq_open, | |
| 458 | + .release = single_release, | |
| 459 | + .read = seq_read, | |
| 460 | + .llseek = seq_lseek, | |
| 461 | +}; | |
| 462 | + | |
| 463 | +/*---------beamforming------------*/ | |
| 464 | +static int wil_bf_debugfs_show(struct seq_file *s, void *data) | |
| 465 | +{ | |
| 466 | + struct wil6210_priv *wil = s->private; | |
| 467 | + seq_printf(s, | |
| 468 | + "TSF : 0x%016llx\n" | |
| 469 | + "TxMCS : %d\n" | |
| 470 | + "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n", | |
| 471 | + wil->stats.tsf, wil->stats.bf_mcs, | |
| 472 | + wil->stats.my_rx_sector, wil->stats.my_tx_sector, | |
| 473 | + wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); | |
| 474 | + return 0; | |
| 475 | +} | |
| 476 | + | |
| 477 | +static int wil_bf_seq_open(struct inode *inode, struct file *file) | |
| 478 | +{ | |
| 479 | + return single_open(file, wil_bf_debugfs_show, inode->i_private); | |
| 480 | +} | |
| 481 | + | |
| 482 | +static const struct file_operations fops_bf = { | |
| 483 | + .open = wil_bf_seq_open, | |
| 484 | + .release = single_release, | |
| 485 | + .read = seq_read, | |
| 486 | + .llseek = seq_lseek, | |
| 487 | +}; | |
| 488 | +/*---------SSID------------*/ | |
| 489 | +static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf, | |
| 490 | + size_t count, loff_t *ppos) | |
| 491 | +{ | |
| 492 | + struct wil6210_priv *wil = file->private_data; | |
| 493 | + struct wireless_dev *wdev = wil_to_wdev(wil); | |
| 494 | + | |
| 495 | + return simple_read_from_buffer(user_buf, count, ppos, | |
| 496 | + wdev->ssid, wdev->ssid_len); | |
| 497 | +} | |
| 498 | + | |
| 499 | +static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf, | |
| 500 | + size_t count, loff_t *ppos) | |
| 501 | +{ | |
| 502 | + struct wil6210_priv *wil = file->private_data; | |
| 503 | + struct wireless_dev *wdev = wil_to_wdev(wil); | |
| 504 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 505 | + | |
| 506 | + if (*ppos != 0) { | |
| 507 | + wil_err(wil, "Unable to set SSID substring from [%d]\n", | |
| 508 | + (int)*ppos); | |
| 509 | + return -EINVAL; | |
| 510 | + } | |
| 511 | + | |
| 512 | + if (count > sizeof(wdev->ssid)) { | |
| 513 | + wil_err(wil, "SSID too long, len = %d\n", (int)count); | |
| 514 | + return -EINVAL; | |
| 515 | + } | |
| 516 | + if (netif_running(ndev)) { | |
| 517 | + wil_err(wil, "Unable to change SSID on running interface\n"); | |
| 518 | + return -EINVAL; | |
| 519 | + } | |
| 520 | + | |
| 521 | + wdev->ssid_len = count; | |
| 522 | + return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos, | |
| 523 | + buf, count); | |
| 524 | +} | |
| 525 | + | |
| 526 | +static const struct file_operations fops_ssid = { | |
| 527 | + .read = wil_read_file_ssid, | |
| 528 | + .write = wil_write_file_ssid, | |
| 529 | + .open = wil_default_open, | |
| 530 | +}; | |
| 531 | + | |
| 532 | +/*----------------*/ | |
| 533 | +int wil6210_debugfs_init(struct wil6210_priv *wil) | |
| 534 | +{ | |
| 535 | + struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, | |
| 536 | + wil_to_wiphy(wil)->debugfsdir); | |
| 537 | + | |
| 538 | + if (IS_ERR_OR_NULL(dbg)) | |
| 539 | + return -ENODEV; | |
| 540 | + | |
| 541 | + debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); | |
| 542 | + debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); | |
| 543 | + debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc); | |
| 544 | + debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg, | |
| 545 | + &dbg_txdesc_index); | |
| 546 | + debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf); | |
| 547 | + debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); | |
| 548 | + debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, | |
| 549 | + &wil->secure_pcp); | |
| 550 | + | |
| 551 | + wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg, | |
| 552 | + HOSTADDR(RGF_USER_USER_ICR)); | |
| 553 | + wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg, | |
| 554 | + HOSTADDR(RGF_DMA_EP_TX_ICR)); | |
| 555 | + wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg, | |
| 556 | + HOSTADDR(RGF_DMA_EP_RX_ICR)); | |
| 557 | + wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg, | |
| 558 | + HOSTADDR(RGF_DMA_EP_MISC_ICR)); | |
| 559 | + wil6210_debugfs_create_pseudo_ISR(wil, dbg); | |
| 560 | + wil6210_debugfs_create_ITR_CNT(wil, dbg); | |
| 561 | + | |
| 562 | + debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr); | |
| 563 | + debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread); | |
| 564 | + | |
| 565 | + debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset); | |
| 566 | + | |
| 567 | + wil->rgf_blob.data = (void * __force)wil->csr + 0; | |
| 568 | + wil->rgf_blob.size = 0xa000; | |
| 569 | + wil_debugfs_create_ioblob("blob_rgf", S_IRUGO, dbg, &wil->rgf_blob); | |
| 570 | + | |
| 571 | + wil->fw_code_blob.data = (void * __force)wil->csr + 0x40000; | |
| 572 | + wil->fw_code_blob.size = 0x40000; | |
| 573 | + wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO, dbg, | |
| 574 | + &wil->fw_code_blob); | |
| 575 | + | |
| 576 | + wil->fw_data_blob.data = (void * __force)wil->csr + 0x80000; | |
| 577 | + wil->fw_data_blob.size = 0x8000; | |
| 578 | + wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO, dbg, | |
| 579 | + &wil->fw_data_blob); | |
| 580 | + | |
| 581 | + wil->fw_peri_blob.data = (void * __force)wil->csr + 0x88000; | |
| 582 | + wil->fw_peri_blob.size = 0x18000; | |
| 583 | + wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO, dbg, | |
| 584 | + &wil->fw_peri_blob); | |
| 585 | + | |
| 586 | + wil->uc_code_blob.data = (void * __force)wil->csr + 0xa0000; | |
| 587 | + wil->uc_code_blob.size = 0x10000; | |
| 588 | + wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO, dbg, | |
| 589 | + &wil->uc_code_blob); | |
| 590 | + | |
| 591 | + wil->uc_data_blob.data = (void * __force)wil->csr + 0xb0000; | |
| 592 | + wil->uc_data_blob.size = 0x4000; | |
| 593 | + wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO, dbg, | |
| 594 | + &wil->uc_data_blob); | |
| 595 | + | |
| 596 | + return 0; | |
| 597 | +} | |
| 598 | + | |
| 599 | +void wil6210_debugfs_remove(struct wil6210_priv *wil) | |
| 600 | +{ | |
| 601 | + debugfs_remove_recursive(wil->debug); | |
| 602 | + wil->debug = NULL; | |
| 603 | +} | |
| @@ -0,0 +1,471 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 11 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 13 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 14 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/interrupt.h> | |
| 18 | + | |
| 19 | +#include "wil6210.h" | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * Theory of operation: | |
| 23 | + * | |
| 24 | + * There is ISR pseudo-cause register, | |
| 25 | + * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE | |
| 26 | + * Its bits represents OR'ed bits from 3 real ISR registers: | |
| 27 | + * TX, RX, and MISC. | |
| 28 | + * | |
| 29 | + * Registers may be configured to either "write 1 to clear" or | |
| 30 | + * "clear on read" mode | |
| 31 | + * | |
| 32 | + * When handling interrupt, one have to mask/unmask interrupts for the | |
| 33 | + * real ISR registers, or hardware may malfunction. | |
| 34 | + * | |
| 35 | + */ | |
| 36 | + | |
| 37 | +#define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL) | |
| 38 | +#define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE | |
| 39 | +#define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ | |
| 40 | + BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) | |
| 41 | +#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT) | |
| 42 | + | |
| 43 | +#define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \ | |
| 44 | + BIT_DMA_PSEUDO_CAUSE_TX | \ | |
| 45 | + BIT_DMA_PSEUDO_CAUSE_MISC)) | |
| 46 | + | |
| 47 | +#if defined(CONFIG_WIL6210_ISR_COR) | |
| 48 | +/* configure to Clear-On-Read mode */ | |
| 49 | +#define WIL_ICR_ICC_VALUE (0xFFFFFFFFUL) | |
| 50 | + | |
| 51 | +static inline void wil_icr_clear(u32 x, void __iomem *addr) | |
| 52 | +{ | |
| 53 | + | |
| 54 | +} | |
| 55 | +#else /* defined(CONFIG_WIL6210_ISR_COR) */ | |
| 56 | +/* configure to Write-1-to-Clear mode */ | |
| 57 | +#define WIL_ICR_ICC_VALUE (0UL) | |
| 58 | + | |
| 59 | +static inline void wil_icr_clear(u32 x, void __iomem *addr) | |
| 60 | +{ | |
| 61 | + iowrite32(x, addr); | |
| 62 | +} | |
| 63 | +#endif /* defined(CONFIG_WIL6210_ISR_COR) */ | |
| 64 | + | |
| 65 | +static inline u32 wil_ioread32_and_clear(void __iomem *addr) | |
| 66 | +{ | |
| 67 | + u32 x = ioread32(addr); | |
| 68 | + | |
| 69 | + wil_icr_clear(x, addr); | |
| 70 | + | |
| 71 | + return x; | |
| 72 | +} | |
| 73 | + | |
| 74 | +static void wil6210_mask_irq_tx(struct wil6210_priv *wil) | |
| 75 | +{ | |
| 76 | + iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | |
| 77 | + HOSTADDR(RGF_DMA_EP_TX_ICR) + | |
| 78 | + offsetof(struct RGF_ICR, IMS)); | |
| 79 | +} | |
| 80 | + | |
| 81 | +static void wil6210_mask_irq_rx(struct wil6210_priv *wil) | |
| 82 | +{ | |
| 83 | + iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | |
| 84 | + HOSTADDR(RGF_DMA_EP_RX_ICR) + | |
| 85 | + offsetof(struct RGF_ICR, IMS)); | |
| 86 | +} | |
| 87 | + | |
| 88 | +static void wil6210_mask_irq_misc(struct wil6210_priv *wil) | |
| 89 | +{ | |
| 90 | + iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | |
| 91 | + HOSTADDR(RGF_DMA_EP_MISC_ICR) + | |
| 92 | + offsetof(struct RGF_ICR, IMS)); | |
| 93 | +} | |
| 94 | + | |
| 95 | +static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) | |
| 96 | +{ | |
| 97 | + wil_dbg_IRQ(wil, "%s()\n", __func__); | |
| 98 | + | |
| 99 | + iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | |
| 100 | + HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); | |
| 101 | + | |
| 102 | + clear_bit(wil_status_irqen, &wil->status); | |
| 103 | +} | |
| 104 | + | |
| 105 | +static void wil6210_unmask_irq_tx(struct wil6210_priv *wil) | |
| 106 | +{ | |
| 107 | + iowrite32(WIL6210_IMC_TX, wil->csr + | |
| 108 | + HOSTADDR(RGF_DMA_EP_TX_ICR) + | |
| 109 | + offsetof(struct RGF_ICR, IMC)); | |
| 110 | +} | |
| 111 | + | |
| 112 | +static void wil6210_unmask_irq_rx(struct wil6210_priv *wil) | |
| 113 | +{ | |
| 114 | + iowrite32(WIL6210_IMC_RX, wil->csr + | |
| 115 | + HOSTADDR(RGF_DMA_EP_RX_ICR) + | |
| 116 | + offsetof(struct RGF_ICR, IMC)); | |
| 117 | +} | |
| 118 | + | |
| 119 | +static void wil6210_unmask_irq_misc(struct wil6210_priv *wil) | |
| 120 | +{ | |
| 121 | + iowrite32(WIL6210_IMC_MISC, wil->csr + | |
| 122 | + HOSTADDR(RGF_DMA_EP_MISC_ICR) + | |
| 123 | + offsetof(struct RGF_ICR, IMC)); | |
| 124 | +} | |
| 125 | + | |
| 126 | +static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) | |
| 127 | +{ | |
| 128 | + wil_dbg_IRQ(wil, "%s()\n", __func__); | |
| 129 | + | |
| 130 | + set_bit(wil_status_irqen, &wil->status); | |
| 131 | + | |
| 132 | + iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr + | |
| 133 | + HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); | |
| 134 | +} | |
| 135 | + | |
| 136 | +void wil6210_disable_irq(struct wil6210_priv *wil) | |
| 137 | +{ | |
| 138 | + wil_dbg_IRQ(wil, "%s()\n", __func__); | |
| 139 | + | |
| 140 | + wil6210_mask_irq_tx(wil); | |
| 141 | + wil6210_mask_irq_rx(wil); | |
| 142 | + wil6210_mask_irq_misc(wil); | |
| 143 | + wil6210_mask_irq_pseudo(wil); | |
| 144 | +} | |
| 145 | + | |
| 146 | +void wil6210_enable_irq(struct wil6210_priv *wil) | |
| 147 | +{ | |
| 148 | + wil_dbg_IRQ(wil, "%s()\n", __func__); | |
| 149 | + | |
| 150 | + iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + | |
| 151 | + offsetof(struct RGF_ICR, ICC)); | |
| 152 | + iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + | |
| 153 | + offsetof(struct RGF_ICR, ICC)); | |
| 154 | + iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + | |
| 155 | + offsetof(struct RGF_ICR, ICC)); | |
| 156 | + | |
| 157 | + wil6210_unmask_irq_pseudo(wil); | |
| 158 | + wil6210_unmask_irq_tx(wil); | |
| 159 | + wil6210_unmask_irq_rx(wil); | |
| 160 | + wil6210_unmask_irq_misc(wil); | |
| 161 | +} | |
| 162 | + | |
| 163 | +static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | |
| 164 | +{ | |
| 165 | + struct wil6210_priv *wil = cookie; | |
| 166 | + u32 isr = wil_ioread32_and_clear(wil->csr + | |
| 167 | + HOSTADDR(RGF_DMA_EP_RX_ICR) + | |
| 168 | + offsetof(struct RGF_ICR, ICR)); | |
| 169 | + | |
| 170 | + wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr); | |
| 171 | + | |
| 172 | + if (!isr) { | |
| 173 | + wil_err(wil, "spurious IRQ: RX\n"); | |
| 174 | + return IRQ_NONE; | |
| 175 | + } | |
| 176 | + | |
| 177 | + wil6210_mask_irq_rx(wil); | |
| 178 | + | |
| 179 | + if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { | |
| 180 | + wil_dbg_IRQ(wil, "RX done\n"); | |
| 181 | + isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; | |
| 182 | + wil_rx_handle(wil); | |
| 183 | + } | |
| 184 | + | |
| 185 | + if (isr) | |
| 186 | + wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); | |
| 187 | + | |
| 188 | + wil6210_unmask_irq_rx(wil); | |
| 189 | + | |
| 190 | + return IRQ_HANDLED; | |
| 191 | +} | |
| 192 | + | |
| 193 | +static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | |
| 194 | +{ | |
| 195 | + struct wil6210_priv *wil = cookie; | |
| 196 | + u32 isr = wil_ioread32_and_clear(wil->csr + | |
| 197 | + HOSTADDR(RGF_DMA_EP_TX_ICR) + | |
| 198 | + offsetof(struct RGF_ICR, ICR)); | |
| 199 | + | |
| 200 | + wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr); | |
| 201 | + | |
| 202 | + if (!isr) { | |
| 203 | + wil_err(wil, "spurious IRQ: TX\n"); | |
| 204 | + return IRQ_NONE; | |
| 205 | + } | |
| 206 | + | |
| 207 | + wil6210_mask_irq_tx(wil); | |
| 208 | + | |
| 209 | + if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { | |
| 210 | + uint i; | |
| 211 | + wil_dbg_IRQ(wil, "TX done\n"); | |
| 212 | + isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; | |
| 213 | + for (i = 0; i < 24; i++) { | |
| 214 | + u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); | |
| 215 | + if (isr & mask) { | |
| 216 | + isr &= ~mask; | |
| 217 | + wil_dbg_IRQ(wil, "TX done(%i)\n", i); | |
| 218 | + wil_tx_complete(wil, i); | |
| 219 | + } | |
| 220 | + } | |
| 221 | + } | |
| 222 | + | |
| 223 | + if (isr) | |
| 224 | + wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); | |
| 225 | + | |
| 226 | + wil6210_unmask_irq_tx(wil); | |
| 227 | + | |
| 228 | + return IRQ_HANDLED; | |
| 229 | +} | |
| 230 | + | |
| 231 | +static irqreturn_t wil6210_irq_misc(int irq, void *cookie) | |
| 232 | +{ | |
| 233 | + struct wil6210_priv *wil = cookie; | |
| 234 | + u32 isr = wil_ioread32_and_clear(wil->csr + | |
| 235 | + HOSTADDR(RGF_DMA_EP_MISC_ICR) + | |
| 236 | + offsetof(struct RGF_ICR, ICR)); | |
| 237 | + | |
| 238 | + wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr); | |
| 239 | + | |
| 240 | + if (!isr) { | |
| 241 | + wil_err(wil, "spurious IRQ: MISC\n"); | |
| 242 | + return IRQ_NONE; | |
| 243 | + } | |
| 244 | + | |
| 245 | + wil6210_mask_irq_misc(wil); | |
| 246 | + | |
| 247 | + if (isr & ISR_MISC_FW_READY) { | |
| 248 | + wil_dbg_IRQ(wil, "IRQ: FW ready\n"); | |
| 249 | + /** | |
| 250 | + * Actual FW ready indicated by the | |
| 251 | + * WMI_FW_READY_EVENTID | |
| 252 | + */ | |
| 253 | + isr &= ~ISR_MISC_FW_READY; | |
| 254 | + } | |
| 255 | + | |
| 256 | + wil->isr_misc = isr; | |
| 257 | + | |
| 258 | + if (isr) { | |
| 259 | + return IRQ_WAKE_THREAD; | |
| 260 | + } else { | |
| 261 | + wil6210_unmask_irq_misc(wil); | |
| 262 | + return IRQ_HANDLED; | |
| 263 | + } | |
| 264 | +} | |
| 265 | + | |
| 266 | +static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) | |
| 267 | +{ | |
| 268 | + struct wil6210_priv *wil = cookie; | |
| 269 | + u32 isr = wil->isr_misc; | |
| 270 | + | |
| 271 | + wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr); | |
| 272 | + | |
| 273 | + if (isr & ISR_MISC_MBOX_EVT) { | |
| 274 | + wil_dbg_IRQ(wil, "MBOX event\n"); | |
| 275 | + wmi_recv_cmd(wil); | |
| 276 | + isr &= ~ISR_MISC_MBOX_EVT; | |
| 277 | + } | |
| 278 | + | |
| 279 | + if (isr) | |
| 280 | + wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr); | |
| 281 | + | |
| 282 | + wil->isr_misc = 0; | |
| 283 | + | |
| 284 | + wil6210_unmask_irq_misc(wil); | |
| 285 | + | |
| 286 | + return IRQ_HANDLED; | |
| 287 | +} | |
| 288 | + | |
| 289 | +/** | |
| 290 | + * thread IRQ handler | |
| 291 | + */ | |
| 292 | +static irqreturn_t wil6210_thread_irq(int irq, void *cookie) | |
| 293 | +{ | |
| 294 | + struct wil6210_priv *wil = cookie; | |
| 295 | + | |
| 296 | + wil_dbg_IRQ(wil, "Thread IRQ\n"); | |
| 297 | + /* Discover real IRQ cause */ | |
| 298 | + if (wil->isr_misc) | |
| 299 | + wil6210_irq_misc_thread(irq, cookie); | |
| 300 | + | |
| 301 | + wil6210_unmask_irq_pseudo(wil); | |
| 302 | + | |
| 303 | + return IRQ_HANDLED; | |
| 304 | +} | |
| 305 | + | |
| 306 | +/* DEBUG | |
| 307 | + * There is subtle bug in hardware that causes IRQ to raise when it should be | |
| 308 | + * masked. It is quite rare and hard to debug. | |
| 309 | + * | |
| 310 | + * Catch irq issue if it happens and print all I can. | |
| 311 | + */ | |
| 312 | +static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) | |
| 313 | +{ | |
| 314 | + if (!test_bit(wil_status_irqen, &wil->status)) { | |
| 315 | + u32 icm_rx = wil_ioread32_and_clear(wil->csr + | |
| 316 | + HOSTADDR(RGF_DMA_EP_RX_ICR) + | |
| 317 | + offsetof(struct RGF_ICR, ICM)); | |
| 318 | + u32 icr_rx = wil_ioread32_and_clear(wil->csr + | |
| 319 | + HOSTADDR(RGF_DMA_EP_RX_ICR) + | |
| 320 | + offsetof(struct RGF_ICR, ICR)); | |
| 321 | + u32 imv_rx = ioread32(wil->csr + | |
| 322 | + HOSTADDR(RGF_DMA_EP_RX_ICR) + | |
| 323 | + offsetof(struct RGF_ICR, IMV)); | |
| 324 | + u32 icm_tx = wil_ioread32_and_clear(wil->csr + | |
| 325 | + HOSTADDR(RGF_DMA_EP_TX_ICR) + | |
| 326 | + offsetof(struct RGF_ICR, ICM)); | |
| 327 | + u32 icr_tx = wil_ioread32_and_clear(wil->csr + | |
| 328 | + HOSTADDR(RGF_DMA_EP_TX_ICR) + | |
| 329 | + offsetof(struct RGF_ICR, ICR)); | |
| 330 | + u32 imv_tx = ioread32(wil->csr + | |
| 331 | + HOSTADDR(RGF_DMA_EP_TX_ICR) + | |
| 332 | + offsetof(struct RGF_ICR, IMV)); | |
| 333 | + u32 icm_misc = wil_ioread32_and_clear(wil->csr + | |
| 334 | + HOSTADDR(RGF_DMA_EP_MISC_ICR) + | |
| 335 | + offsetof(struct RGF_ICR, ICM)); | |
| 336 | + u32 icr_misc = wil_ioread32_and_clear(wil->csr + | |
| 337 | + HOSTADDR(RGF_DMA_EP_MISC_ICR) + | |
| 338 | + offsetof(struct RGF_ICR, ICR)); | |
| 339 | + u32 imv_misc = ioread32(wil->csr + | |
| 340 | + HOSTADDR(RGF_DMA_EP_MISC_ICR) + | |
| 341 | + offsetof(struct RGF_ICR, IMV)); | |
| 342 | + wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n" | |
| 343 | + "Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" | |
| 344 | + "Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" | |
| 345 | + "Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n", | |
| 346 | + pseudo_cause, | |
| 347 | + icm_rx, icr_rx, imv_rx, | |
| 348 | + icm_tx, icr_tx, imv_tx, | |
| 349 | + icm_misc, icr_misc, imv_misc); | |
| 350 | + | |
| 351 | + return -EINVAL; | |
| 352 | + } | |
| 353 | + | |
| 354 | + return 0; | |
| 355 | +} | |
| 356 | + | |
| 357 | +static irqreturn_t wil6210_hardirq(int irq, void *cookie) | |
| 358 | +{ | |
| 359 | + irqreturn_t rc = IRQ_HANDLED; | |
| 360 | + struct wil6210_priv *wil = cookie; | |
| 361 | + u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); | |
| 362 | + | |
| 363 | + /** | |
| 364 | + * pseudo_cause is Clear-On-Read, no need to ACK | |
| 365 | + */ | |
| 366 | + if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)) | |
| 367 | + return IRQ_NONE; | |
| 368 | + | |
| 369 | + /* FIXME: IRQ mask debug */ | |
| 370 | + if (wil6210_debug_irq_mask(wil, pseudo_cause)) | |
| 371 | + return IRQ_NONE; | |
| 372 | + | |
| 373 | + wil6210_mask_irq_pseudo(wil); | |
| 374 | + | |
| 375 | + /* Discover real IRQ cause | |
| 376 | + * There are 2 possible phases for every IRQ: | |
| 377 | + * - hard IRQ handler called right here | |
| 378 | + * - threaded handler called later | |
| 379 | + * | |
| 380 | + * Hard IRQ handler reads and clears ISR. | |
| 381 | + * | |
| 382 | + * If threaded handler requested, hard IRQ handler | |
| 383 | + * returns IRQ_WAKE_THREAD and saves ISR register value | |
| 384 | + * for the threaded handler use. | |
| 385 | + * | |
| 386 | + * voting for wake thread - need at least 1 vote | |
| 387 | + */ | |
| 388 | + if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) && | |
| 389 | + (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD)) | |
| 390 | + rc = IRQ_WAKE_THREAD; | |
| 391 | + | |
| 392 | + if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) && | |
| 393 | + (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD)) | |
| 394 | + rc = IRQ_WAKE_THREAD; | |
| 395 | + | |
| 396 | + if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) && | |
| 397 | + (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD)) | |
| 398 | + rc = IRQ_WAKE_THREAD; | |
| 399 | + | |
| 400 | + /* if thread is requested, it will unmask IRQ */ | |
| 401 | + if (rc != IRQ_WAKE_THREAD) | |
| 402 | + wil6210_unmask_irq_pseudo(wil); | |
| 403 | + | |
| 404 | + wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause); | |
| 405 | + | |
| 406 | + return rc; | |
| 407 | +} | |
| 408 | + | |
| 409 | +static int wil6210_request_3msi(struct wil6210_priv *wil, int irq) | |
| 410 | +{ | |
| 411 | + int rc; | |
| 412 | + /* | |
| 413 | + * IRQ's are in the following order: | |
| 414 | + * - Tx | |
| 415 | + * - Rx | |
| 416 | + * - Misc | |
| 417 | + */ | |
| 418 | + | |
| 419 | + rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED, | |
| 420 | + WIL_NAME"_tx", wil); | |
| 421 | + if (rc) | |
| 422 | + return rc; | |
| 423 | + | |
| 424 | + rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED, | |
| 425 | + WIL_NAME"_rx", wil); | |
| 426 | + if (rc) | |
| 427 | + goto free0; | |
| 428 | + | |
| 429 | + rc = request_threaded_irq(irq + 2, wil6210_irq_misc, | |
| 430 | + wil6210_irq_misc_thread, | |
| 431 | + IRQF_SHARED, WIL_NAME"_misc", wil); | |
| 432 | + if (rc) | |
| 433 | + goto free1; | |
| 434 | + | |
| 435 | + return 0; | |
| 436 | + /* error branch */ | |
| 437 | +free1: | |
| 438 | + free_irq(irq + 1, wil); | |
| 439 | +free0: | |
| 440 | + free_irq(irq, wil); | |
| 441 | + | |
| 442 | + return rc; | |
| 443 | +} | |
| 444 | + | |
| 445 | +int wil6210_init_irq(struct wil6210_priv *wil, int irq) | |
| 446 | +{ | |
| 447 | + int rc; | |
| 448 | + if (wil->n_msi == 3) | |
| 449 | + rc = wil6210_request_3msi(wil, irq); | |
| 450 | + else | |
| 451 | + rc = request_threaded_irq(irq, wil6210_hardirq, | |
| 452 | + wil6210_thread_irq, | |
| 453 | + wil->n_msi ? 0 : IRQF_SHARED, | |
| 454 | + WIL_NAME, wil); | |
| 455 | + if (rc) | |
| 456 | + return rc; | |
| 457 | + | |
| 458 | + wil6210_enable_irq(wil); | |
| 459 | + | |
| 460 | + return 0; | |
| 461 | +} | |
| 462 | + | |
| 463 | +void wil6210_fini_irq(struct wil6210_priv *wil, int irq) | |
| 464 | +{ | |
| 465 | + wil6210_disable_irq(wil); | |
| 466 | + free_irq(irq, wil); | |
| 467 | + if (wil->n_msi == 3) { | |
| 468 | + free_irq(irq + 1, wil); | |
| 469 | + free_irq(irq + 2, wil); | |
| 470 | + } | |
| 471 | +} | |
| @@ -0,0 +1,407 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 11 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 13 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 14 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/kernel.h> | |
| 18 | +#include <linux/netdevice.h> | |
| 19 | +#include <linux/sched.h> | |
| 20 | +#include <linux/ieee80211.h> | |
| 21 | +#include <linux/wireless.h> | |
| 22 | +#include <linux/slab.h> | |
| 23 | +#include <linux/moduleparam.h> | |
| 24 | +#include <linux/if_arp.h> | |
| 25 | + | |
| 26 | +#include "wil6210.h" | |
| 27 | + | |
| 28 | +/* | |
| 29 | + * Due to a hardware issue, | |
| 30 | + * one has to read/write to/from NIC in 32-bit chunks; | |
| 31 | + * regular memcpy_fromio and siblings will | |
| 32 | + * not work on 64-bit platform - it uses 64-bit transactions | |
| 33 | + * | |
| 34 | + * Force 32-bit transactions to enable NIC on 64-bit platforms | |
| 35 | + * | |
| 36 | + * To avoid byte swap on big endian host, __raw_{read|write}l | |
| 37 | + * should be used - {read|write}l would swap bytes to provide | |
| 38 | + * little endian on PCI value in host endianness. | |
| 39 | + */ | |
| 40 | +void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, | |
| 41 | + size_t count) | |
| 42 | +{ | |
| 43 | + u32 *d = dst; | |
| 44 | + const volatile u32 __iomem *s = src; | |
| 45 | + | |
| 46 | + /* size_t is unsigned, if (count%4 != 0) it will wrap */ | |
| 47 | + for (count += 4; count > 4; count -= 4) | |
| 48 | + *d++ = __raw_readl(s++); | |
| 49 | +} | |
| 50 | + | |
| 51 | +void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, | |
| 52 | + size_t count) | |
| 53 | +{ | |
| 54 | + volatile u32 __iomem *d = dst; | |
| 55 | + const u32 *s = src; | |
| 56 | + | |
| 57 | + for (count += 4; count > 4; count -= 4) | |
| 58 | + __raw_writel(*s++, d++); | |
| 59 | +} | |
| 60 | + | |
| 61 | +static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) | |
| 62 | +{ | |
| 63 | + uint i; | |
| 64 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 65 | + struct wireless_dev *wdev = wil->wdev; | |
| 66 | + | |
| 67 | + wil_dbg(wil, "%s()\n", __func__); | |
| 68 | + | |
| 69 | + wil_link_off(wil); | |
| 70 | + clear_bit(wil_status_fwconnected, &wil->status); | |
| 71 | + | |
| 72 | + switch (wdev->sme_state) { | |
| 73 | + case CFG80211_SME_CONNECTED: | |
| 74 | + cfg80211_disconnected(ndev, WLAN_STATUS_UNSPECIFIED_FAILURE, | |
| 75 | + NULL, 0, GFP_KERNEL); | |
| 76 | + break; | |
| 77 | + case CFG80211_SME_CONNECTING: | |
| 78 | + cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, | |
| 79 | + WLAN_STATUS_UNSPECIFIED_FAILURE, | |
| 80 | + GFP_KERNEL); | |
| 81 | + break; | |
| 82 | + default: | |
| 83 | + ; | |
| 84 | + } | |
| 85 | + | |
| 86 | + for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) | |
| 87 | + wil_vring_fini_tx(wil, i); | |
| 88 | +} | |
| 89 | + | |
| 90 | +static void wil_disconnect_worker(struct work_struct *work) | |
| 91 | +{ | |
| 92 | + struct wil6210_priv *wil = container_of(work, | |
| 93 | + struct wil6210_priv, disconnect_worker); | |
| 94 | + | |
| 95 | + _wil6210_disconnect(wil, NULL); | |
| 96 | +} | |
| 97 | + | |
| 98 | +static void wil_connect_timer_fn(ulong x) | |
| 99 | +{ | |
| 100 | + struct wil6210_priv *wil = (void *)x; | |
| 101 | + | |
| 102 | + wil_dbg(wil, "Connect timeout\n"); | |
| 103 | + | |
| 104 | + /* reschedule to thread context - disconnect won't | |
| 105 | + * run from atomic context | |
| 106 | + */ | |
| 107 | + schedule_work(&wil->disconnect_worker); | |
| 108 | +} | |
| 109 | + | |
| 110 | +int wil_priv_init(struct wil6210_priv *wil) | |
| 111 | +{ | |
| 112 | + wil_dbg(wil, "%s()\n", __func__); | |
| 113 | + | |
| 114 | + mutex_init(&wil->mutex); | |
| 115 | + mutex_init(&wil->wmi_mutex); | |
| 116 | + | |
| 117 | + init_completion(&wil->wmi_ready); | |
| 118 | + | |
| 119 | + wil->pending_connect_cid = -1; | |
| 120 | + setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); | |
| 121 | + | |
| 122 | + INIT_WORK(&wil->wmi_connect_worker, wmi_connect_worker); | |
| 123 | + INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); | |
| 124 | + INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); | |
| 125 | + | |
| 126 | + INIT_LIST_HEAD(&wil->pending_wmi_ev); | |
| 127 | + spin_lock_init(&wil->wmi_ev_lock); | |
| 128 | + | |
| 129 | + wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi"); | |
| 130 | + if (!wil->wmi_wq) | |
| 131 | + return -EAGAIN; | |
| 132 | + | |
| 133 | + wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect"); | |
| 134 | + if (!wil->wmi_wq_conn) { | |
| 135 | + destroy_workqueue(wil->wmi_wq); | |
| 136 | + return -EAGAIN; | |
| 137 | + } | |
| 138 | + | |
| 139 | + /* make shadow copy of registers that should not change on run time */ | |
| 140 | + wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, | |
| 141 | + sizeof(struct wil6210_mbox_ctl)); | |
| 142 | + wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); | |
| 143 | + wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); | |
| 144 | + | |
| 145 | + return 0; | |
| 146 | +} | |
| 147 | + | |
| 148 | +void wil6210_disconnect(struct wil6210_priv *wil, void *bssid) | |
| 149 | +{ | |
| 150 | + del_timer_sync(&wil->connect_timer); | |
| 151 | + _wil6210_disconnect(wil, bssid); | |
| 152 | +} | |
| 153 | + | |
| 154 | +void wil_priv_deinit(struct wil6210_priv *wil) | |
| 155 | +{ | |
| 156 | + cancel_work_sync(&wil->disconnect_worker); | |
| 157 | + wil6210_disconnect(wil, NULL); | |
| 158 | + wmi_event_flush(wil); | |
| 159 | + destroy_workqueue(wil->wmi_wq_conn); | |
| 160 | + destroy_workqueue(wil->wmi_wq); | |
| 161 | +} | |
| 162 | + | |
| 163 | +static void wil_target_reset(struct wil6210_priv *wil) | |
| 164 | +{ | |
| 165 | + wil_dbg(wil, "Resetting...\n"); | |
| 166 | + | |
| 167 | + /* register write */ | |
| 168 | +#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) | |
| 169 | + /* register set = read, OR, write */ | |
| 170 | +#define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ | |
| 171 | + wil->csr + HOSTADDR(a)) | |
| 172 | + | |
| 173 | + /* hpal_perst_from_pad_src_n_mask */ | |
| 174 | + S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); | |
| 175 | + /* car_perst_rst_src_n_mask */ | |
| 176 | + S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); | |
| 177 | + | |
| 178 | + W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ | |
| 179 | + W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ | |
| 180 | + | |
| 181 | + msleep(100); | |
| 182 | + | |
| 183 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); | |
| 184 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); | |
| 185 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170); | |
| 186 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); | |
| 187 | + | |
| 188 | + msleep(100); | |
| 189 | + | |
| 190 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); | |
| 191 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); | |
| 192 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); | |
| 193 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); | |
| 194 | + | |
| 195 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); | |
| 196 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); | |
| 197 | + W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); | |
| 198 | + | |
| 199 | + msleep(2000); | |
| 200 | + | |
| 201 | + W(RGF_USER_USER_CPU_0, BIT(0)); /* user_cpu_man_de_rst */ | |
| 202 | + | |
| 203 | + msleep(2000); | |
| 204 | + | |
| 205 | + wil_dbg(wil, "Reset completed\n"); | |
| 206 | + | |
| 207 | +#undef W | |
| 208 | +#undef S | |
| 209 | +} | |
| 210 | + | |
| 211 | +void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) | |
| 212 | +{ | |
| 213 | + le32_to_cpus(&r->base); | |
| 214 | + le16_to_cpus(&r->entry_size); | |
| 215 | + le16_to_cpus(&r->size); | |
| 216 | + le32_to_cpus(&r->tail); | |
| 217 | + le32_to_cpus(&r->head); | |
| 218 | +} | |
| 219 | + | |
| 220 | +static int wil_wait_for_fw_ready(struct wil6210_priv *wil) | |
| 221 | +{ | |
| 222 | + ulong to = msecs_to_jiffies(1000); | |
| 223 | + ulong left = wait_for_completion_timeout(&wil->wmi_ready, to); | |
| 224 | + if (0 == left) { | |
| 225 | + wil_err(wil, "Firmware not ready\n"); | |
| 226 | + return -ETIME; | |
| 227 | + } else { | |
| 228 | + wil_dbg(wil, "FW ready after %d ms\n", | |
| 229 | + jiffies_to_msecs(to-left)); | |
| 230 | + } | |
| 231 | + return 0; | |
| 232 | +} | |
| 233 | + | |
| 234 | +/* | |
| 235 | + * We reset all the structures, and we reset the UMAC. | |
| 236 | + * After calling this routine, you're expected to reload | |
| 237 | + * the firmware. | |
| 238 | + */ | |
| 239 | +int wil_reset(struct wil6210_priv *wil) | |
| 240 | +{ | |
| 241 | + int rc; | |
| 242 | + | |
| 243 | + cancel_work_sync(&wil->disconnect_worker); | |
| 244 | + wil6210_disconnect(wil, NULL); | |
| 245 | + | |
| 246 | + wmi_event_flush(wil); | |
| 247 | + | |
| 248 | + flush_workqueue(wil->wmi_wq); | |
| 249 | + flush_workqueue(wil->wmi_wq_conn); | |
| 250 | + | |
| 251 | + wil6210_disable_irq(wil); | |
| 252 | + wil->status = 0; | |
| 253 | + | |
| 254 | + /* TODO: put MAC in reset */ | |
| 255 | + wil_target_reset(wil); | |
| 256 | + | |
| 257 | + /* init after reset */ | |
| 258 | + wil->pending_connect_cid = -1; | |
| 259 | + INIT_COMPLETION(wil->wmi_ready); | |
| 260 | + | |
| 261 | + /* make shadow copy of registers that should not change on run time */ | |
| 262 | + wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, | |
| 263 | + sizeof(struct wil6210_mbox_ctl)); | |
| 264 | + wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); | |
| 265 | + wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); | |
| 266 | + | |
| 267 | + /* TODO: release MAC reset */ | |
| 268 | + wil6210_enable_irq(wil); | |
| 269 | + | |
| 270 | + /* we just started MAC, wait for FW ready */ | |
| 271 | + rc = wil_wait_for_fw_ready(wil); | |
| 272 | + | |
| 273 | + return rc; | |
| 274 | +} | |
| 275 | + | |
| 276 | + | |
| 277 | +void wil_link_on(struct wil6210_priv *wil) | |
| 278 | +{ | |
| 279 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 280 | + | |
| 281 | + wil_dbg(wil, "%s()\n", __func__); | |
| 282 | + | |
| 283 | + netif_carrier_on(ndev); | |
| 284 | + netif_tx_wake_all_queues(ndev); | |
| 285 | +} | |
| 286 | + | |
| 287 | +void wil_link_off(struct wil6210_priv *wil) | |
| 288 | +{ | |
| 289 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 290 | + | |
| 291 | + wil_dbg(wil, "%s()\n", __func__); | |
| 292 | + | |
| 293 | + netif_tx_stop_all_queues(ndev); | |
| 294 | + netif_carrier_off(ndev); | |
| 295 | +} | |
| 296 | + | |
| 297 | +static int __wil_up(struct wil6210_priv *wil) | |
| 298 | +{ | |
| 299 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 300 | + struct wireless_dev *wdev = wil->wdev; | |
| 301 | + struct ieee80211_channel *channel = wdev->preset_chandef.chan; | |
| 302 | + int rc; | |
| 303 | + int bi; | |
| 304 | + u16 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); | |
| 305 | + | |
| 306 | + rc = wil_reset(wil); | |
| 307 | + if (rc) | |
| 308 | + return rc; | |
| 309 | + | |
| 310 | + /* FIXME Firmware works now in PBSS mode(ToDS=0, FromDS=0) */ | |
| 311 | + wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC); | |
| 312 | + switch (wdev->iftype) { | |
| 313 | + case NL80211_IFTYPE_STATION: | |
| 314 | + wil_dbg(wil, "type: STATION\n"); | |
| 315 | + bi = 0; | |
| 316 | + ndev->type = ARPHRD_ETHER; | |
| 317 | + break; | |
| 318 | + case NL80211_IFTYPE_AP: | |
| 319 | + wil_dbg(wil, "type: AP\n"); | |
| 320 | + bi = 100; | |
| 321 | + ndev->type = ARPHRD_ETHER; | |
| 322 | + break; | |
| 323 | + case NL80211_IFTYPE_P2P_CLIENT: | |
| 324 | + wil_dbg(wil, "type: P2P_CLIENT\n"); | |
| 325 | + bi = 0; | |
| 326 | + ndev->type = ARPHRD_ETHER; | |
| 327 | + break; | |
| 328 | + case NL80211_IFTYPE_P2P_GO: | |
| 329 | + wil_dbg(wil, "type: P2P_GO\n"); | |
| 330 | + bi = 100; | |
| 331 | + ndev->type = ARPHRD_ETHER; | |
| 332 | + break; | |
| 333 | + case NL80211_IFTYPE_MONITOR: | |
| 334 | + wil_dbg(wil, "type: Monitor\n"); | |
| 335 | + bi = 0; | |
| 336 | + ndev->type = ARPHRD_IEEE80211_RADIOTAP; | |
| 337 | + /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */ | |
| 338 | + break; | |
| 339 | + default: | |
| 340 | + return -EOPNOTSUPP; | |
| 341 | + } | |
| 342 | + | |
| 343 | + /* Apply profile in the following order: */ | |
| 344 | + /* SSID and channel for the AP */ | |
| 345 | + switch (wdev->iftype) { | |
| 346 | + case NL80211_IFTYPE_AP: | |
| 347 | + case NL80211_IFTYPE_P2P_GO: | |
| 348 | + if (wdev->ssid_len == 0) { | |
| 349 | + wil_err(wil, "SSID not set\n"); | |
| 350 | + return -EINVAL; | |
| 351 | + } | |
| 352 | + wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid); | |
| 353 | + if (channel) | |
| 354 | + wmi_set_channel(wil, channel->hw_value); | |
| 355 | + break; | |
| 356 | + default: | |
| 357 | + ; | |
| 358 | + } | |
| 359 | + | |
| 360 | + /* MAC address - pre-requisite for other commands */ | |
| 361 | + wmi_set_mac_address(wil, ndev->dev_addr); | |
| 362 | + | |
| 363 | + /* Set up beaconing if required. */ | |
| 364 | + rc = wmi_set_bcon(wil, bi, wmi_nettype); | |
| 365 | + if (rc) | |
| 366 | + return rc; | |
| 367 | + | |
| 368 | + /* Rx VRING. After MAC and beacon */ | |
| 369 | + wil_rx_init(wil); | |
| 370 | + | |
| 371 | + return 0; | |
| 372 | +} | |
| 373 | + | |
| 374 | +int wil_up(struct wil6210_priv *wil) | |
| 375 | +{ | |
| 376 | + int rc; | |
| 377 | + | |
| 378 | + mutex_lock(&wil->mutex); | |
| 379 | + rc = __wil_up(wil); | |
| 380 | + mutex_unlock(&wil->mutex); | |
| 381 | + | |
| 382 | + return rc; | |
| 383 | +} | |
| 384 | + | |
| 385 | +static int __wil_down(struct wil6210_priv *wil) | |
| 386 | +{ | |
| 387 | + if (wil->scan_request) { | |
| 388 | + cfg80211_scan_done(wil->scan_request, true); | |
| 389 | + wil->scan_request = NULL; | |
| 390 | + } | |
| 391 | + | |
| 392 | + wil6210_disconnect(wil, NULL); | |
| 393 | + wil_rx_fini(wil); | |
| 394 | + | |
| 395 | + return 0; | |
| 396 | +} | |
| 397 | + | |
| 398 | +int wil_down(struct wil6210_priv *wil) | |
| 399 | +{ | |
| 400 | + int rc; | |
| 401 | + | |
| 402 | + mutex_lock(&wil->mutex); | |
| 403 | + rc = __wil_down(wil); | |
| 404 | + mutex_unlock(&wil->mutex); | |
| 405 | + | |
| 406 | + return rc; | |
| 407 | +} | |
| @@ -0,0 +1,157 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 11 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 13 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 14 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/module.h> | |
| 18 | +#include <linux/netdevice.h> | |
| 19 | +#include <linux/etherdevice.h> | |
| 20 | +#include <linux/slab.h> | |
| 21 | + | |
| 22 | +#include "wil6210.h" | |
| 23 | + | |
| 24 | +static int wil_open(struct net_device *ndev) | |
| 25 | +{ | |
| 26 | + struct wil6210_priv *wil = ndev_to_wil(ndev); | |
| 27 | + | |
| 28 | + return wil_up(wil); | |
| 29 | +} | |
| 30 | + | |
| 31 | +static int wil_stop(struct net_device *ndev) | |
| 32 | +{ | |
| 33 | + struct wil6210_priv *wil = ndev_to_wil(ndev); | |
| 34 | + | |
| 35 | + return wil_down(wil); | |
| 36 | +} | |
| 37 | + | |
| 38 | +/* | |
| 39 | + * AC to queue mapping | |
| 40 | + * | |
| 41 | + * AC_VO -> queue 3 | |
| 42 | + * AC_VI -> queue 2 | |
| 43 | + * AC_BE -> queue 1 | |
| 44 | + * AC_BK -> queue 0 | |
| 45 | + */ | |
| 46 | +static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb) | |
| 47 | +{ | |
| 48 | + static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; | |
| 49 | + struct wil6210_priv *wil = ndev_to_wil(ndev); | |
| 50 | + u16 rc; | |
| 51 | + | |
| 52 | + skb->priority = cfg80211_classify8021d(skb); | |
| 53 | + | |
| 54 | + rc = wil_1d_to_queue[skb->priority]; | |
| 55 | + | |
| 56 | + wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority, | |
| 57 | + (int)rc); | |
| 58 | + | |
| 59 | + return rc; | |
| 60 | +} | |
| 61 | + | |
| 62 | +static const struct net_device_ops wil_netdev_ops = { | |
| 63 | + .ndo_open = wil_open, | |
| 64 | + .ndo_stop = wil_stop, | |
| 65 | + .ndo_start_xmit = wil_start_xmit, | |
| 66 | + .ndo_select_queue = wil_select_queue, | |
| 67 | + .ndo_set_mac_address = eth_mac_addr, | |
| 68 | + .ndo_validate_addr = eth_validate_addr, | |
| 69 | +}; | |
| 70 | + | |
| 71 | +void *wil_if_alloc(struct device *dev, void __iomem *csr) | |
| 72 | +{ | |
| 73 | + struct net_device *ndev; | |
| 74 | + struct wireless_dev *wdev; | |
| 75 | + struct wil6210_priv *wil; | |
| 76 | + struct ieee80211_channel *ch; | |
| 77 | + int rc = 0; | |
| 78 | + | |
| 79 | + wdev = wil_cfg80211_init(dev); | |
| 80 | + if (IS_ERR(wdev)) { | |
| 81 | + dev_err(dev, "wil_cfg80211_init failed\n"); | |
| 82 | + return wdev; | |
| 83 | + } | |
| 84 | + | |
| 85 | + wil = wdev_to_wil(wdev); | |
| 86 | + wil->csr = csr; | |
| 87 | + wil->wdev = wdev; | |
| 88 | + | |
| 89 | + rc = wil_priv_init(wil); | |
| 90 | + if (rc) { | |
| 91 | + dev_err(dev, "wil_priv_init failed\n"); | |
| 92 | + goto out_wdev; | |
| 93 | + } | |
| 94 | + | |
| 95 | + wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */ | |
| 96 | + /* default monitor channel */ | |
| 97 | + ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; | |
| 98 | + cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); | |
| 99 | + | |
| 100 | + ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1); | |
| 101 | + if (!ndev) { | |
| 102 | + dev_err(dev, "alloc_netdev_mqs failed\n"); | |
| 103 | + rc = -ENOMEM; | |
| 104 | + goto out_priv; | |
| 105 | + } | |
| 106 | + | |
| 107 | + ndev->netdev_ops = &wil_netdev_ops; | |
| 108 | + ndev->ieee80211_ptr = wdev; | |
| 109 | + SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); | |
| 110 | + wdev->netdev = ndev; | |
| 111 | + | |
| 112 | + wil_link_off(wil); | |
| 113 | + | |
| 114 | + return wil; | |
| 115 | + | |
| 116 | + out_priv: | |
| 117 | + wil_priv_deinit(wil); | |
| 118 | + | |
| 119 | + out_wdev: | |
| 120 | + wil_wdev_free(wil); | |
| 121 | + | |
| 122 | + return ERR_PTR(rc); | |
| 123 | +} | |
| 124 | + | |
| 125 | +void wil_if_free(struct wil6210_priv *wil) | |
| 126 | +{ | |
| 127 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 128 | + if (!ndev) | |
| 129 | + return; | |
| 130 | + | |
| 131 | + free_netdev(ndev); | |
| 132 | + wil_priv_deinit(wil); | |
| 133 | + wil_wdev_free(wil); | |
| 134 | +} | |
| 135 | + | |
| 136 | +int wil_if_add(struct wil6210_priv *wil) | |
| 137 | +{ | |
| 138 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 139 | + int rc; | |
| 140 | + | |
| 141 | + rc = register_netdev(ndev); | |
| 142 | + if (rc < 0) { | |
| 143 | + dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc); | |
| 144 | + return rc; | |
| 145 | + } | |
| 146 | + | |
| 147 | + wil_link_off(wil); | |
| 148 | + | |
| 149 | + return 0; | |
| 150 | +} | |
| 151 | + | |
| 152 | +void wil_if_remove(struct wil6210_priv *wil) | |
| 153 | +{ | |
| 154 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 155 | + | |
| 156 | + unregister_netdev(ndev); | |
| 157 | +} | |
| @@ -0,0 +1,223 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 11 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 13 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 14 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/kernel.h> | |
| 18 | +#include <linux/module.h> | |
| 19 | +#include <linux/slab.h> | |
| 20 | +#include <linux/netdevice.h> | |
| 21 | +#include <linux/debugfs.h> | |
| 22 | +#include <linux/pci.h> | |
| 23 | +#include <linux/moduleparam.h> | |
| 24 | + | |
| 25 | +#include "wil6210.h" | |
| 26 | + | |
| 27 | +static int use_msi = 1; | |
| 28 | +module_param(use_msi, int, S_IRUGO); | |
| 29 | +MODULE_PARM_DESC(use_msi, | |
| 30 | + " Use MSI interrupt: " | |
| 31 | + "0 - don't, 1 - (default) - single, or 3"); | |
| 32 | + | |
| 33 | +/* Bus ops */ | |
| 34 | +static int wil_if_pcie_enable(struct wil6210_priv *wil) | |
| 35 | +{ | |
| 36 | + struct pci_dev *pdev = wil->pdev; | |
| 37 | + int rc; | |
| 38 | + | |
| 39 | + pci_set_master(pdev); | |
| 40 | + | |
| 41 | + /* | |
| 42 | + * how many MSI interrupts to request? | |
| 43 | + */ | |
| 44 | + switch (use_msi) { | |
| 45 | + case 3: | |
| 46 | + case 1: | |
| 47 | + case 0: | |
| 48 | + break; | |
| 49 | + default: | |
| 50 | + wil_err(wil, "Invalid use_msi=%d, default to 1\n", | |
| 51 | + use_msi); | |
| 52 | + use_msi = 1; | |
| 53 | + } | |
| 54 | + wil->n_msi = use_msi; | |
| 55 | + if (wil->n_msi) { | |
| 56 | + wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi); | |
| 57 | + rc = pci_enable_msi_block(pdev, wil->n_msi); | |
| 58 | + if (rc && (wil->n_msi == 3)) { | |
| 59 | + wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); | |
| 60 | + wil->n_msi = 1; | |
| 61 | + rc = pci_enable_msi_block(pdev, wil->n_msi); | |
| 62 | + } | |
| 63 | + if (rc) { | |
| 64 | + wil_err(wil, "pci_enable_msi failed, use INTx\n"); | |
| 65 | + wil->n_msi = 0; | |
| 66 | + } | |
| 67 | + } else { | |
| 68 | + wil_dbg(wil, "MSI interrupts disabled, use INTx\n"); | |
| 69 | + } | |
| 70 | + | |
| 71 | + rc = wil6210_init_irq(wil, pdev->irq); | |
| 72 | + if (rc) | |
| 73 | + goto stop_master; | |
| 74 | + | |
| 75 | + /* need reset here to obtain MAC */ | |
| 76 | + rc = wil_reset(wil); | |
| 77 | + if (rc) | |
| 78 | + goto release_irq; | |
| 79 | + | |
| 80 | + return 0; | |
| 81 | + | |
| 82 | + release_irq: | |
| 83 | + wil6210_fini_irq(wil, pdev->irq); | |
| 84 | + /* safe to call if no MSI */ | |
| 85 | + pci_disable_msi(pdev); | |
| 86 | + stop_master: | |
| 87 | + pci_clear_master(pdev); | |
| 88 | + return rc; | |
| 89 | +} | |
| 90 | + | |
| 91 | +static int wil_if_pcie_disable(struct wil6210_priv *wil) | |
| 92 | +{ | |
| 93 | + struct pci_dev *pdev = wil->pdev; | |
| 94 | + | |
| 95 | + pci_clear_master(pdev); | |
| 96 | + /* disable and release IRQ */ | |
| 97 | + wil6210_fini_irq(wil, pdev->irq); | |
| 98 | + /* safe to call if no MSI */ | |
| 99 | + pci_disable_msi(pdev); | |
| 100 | + /* TODO: disable HW */ | |
| 101 | + | |
| 102 | + return 0; | |
| 103 | +} | |
| 104 | + | |
| 105 | +static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |
| 106 | +{ | |
| 107 | + struct wil6210_priv *wil; | |
| 108 | + struct device *dev = &pdev->dev; | |
| 109 | + void __iomem *csr; | |
| 110 | + int rc; | |
| 111 | + | |
| 112 | + /* check HW */ | |
| 113 | + dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n", | |
| 114 | + (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); | |
| 115 | + | |
| 116 | + if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { | |
| 117 | + dev_err(&pdev->dev, "Not " WIL_NAME "? " | |
| 118 | + "BAR0 size is %lu while expecting %lu\n", | |
| 119 | + (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE); | |
| 120 | + return -ENODEV; | |
| 121 | + } | |
| 122 | + | |
| 123 | + rc = pci_enable_device(pdev); | |
| 124 | + if (rc) { | |
| 125 | + dev_err(&pdev->dev, "pci_enable_device failed\n"); | |
| 126 | + return -ENODEV; | |
| 127 | + } | |
| 128 | + /* rollback to err_disable_pdev */ | |
| 129 | + | |
| 130 | + rc = pci_request_region(pdev, 0, WIL_NAME); | |
| 131 | + if (rc) { | |
| 132 | + dev_err(&pdev->dev, "pci_request_region failed\n"); | |
| 133 | + goto err_disable_pdev; | |
| 134 | + } | |
| 135 | + /* rollback to err_release_reg */ | |
| 136 | + | |
| 137 | + csr = pci_ioremap_bar(pdev, 0); | |
| 138 | + if (!csr) { | |
| 139 | + dev_err(&pdev->dev, "pci_ioremap_bar failed\n"); | |
| 140 | + rc = -ENODEV; | |
| 141 | + goto err_release_reg; | |
| 142 | + } | |
| 143 | + /* rollback to err_iounmap */ | |
| 144 | + dev_info(&pdev->dev, "CSR at %pR -> %p\n", &pdev->resource[0], csr); | |
| 145 | + | |
| 146 | + wil = wil_if_alloc(dev, csr); | |
| 147 | + if (IS_ERR(wil)) { | |
| 148 | + rc = (int)PTR_ERR(wil); | |
| 149 | + dev_err(dev, "wil_if_alloc failed: %d\n", rc); | |
| 150 | + goto err_iounmap; | |
| 151 | + } | |
| 152 | + /* rollback to if_free */ | |
| 153 | + | |
| 154 | + pci_set_drvdata(pdev, wil); | |
| 155 | + wil->pdev = pdev; | |
| 156 | + | |
| 157 | + /* FW should raise IRQ when ready */ | |
| 158 | + rc = wil_if_pcie_enable(wil); | |
| 159 | + if (rc) { | |
| 160 | + wil_err(wil, "Enable device failed\n"); | |
| 161 | + goto if_free; | |
| 162 | + } | |
| 163 | + /* rollback to bus_disable */ | |
| 164 | + | |
| 165 | + rc = wil_if_add(wil); | |
| 166 | + if (rc) { | |
| 167 | + wil_err(wil, "wil_if_add failed: %d\n", rc); | |
| 168 | + goto bus_disable; | |
| 169 | + } | |
| 170 | + | |
| 171 | + wil6210_debugfs_init(wil); | |
| 172 | + | |
| 173 | + /* check FW is alive */ | |
| 174 | + wmi_echo(wil); | |
| 175 | + | |
| 176 | + return 0; | |
| 177 | + | |
| 178 | + bus_disable: | |
| 179 | + wil_if_pcie_disable(wil); | |
| 180 | + if_free: | |
| 181 | + wil_if_free(wil); | |
| 182 | + err_iounmap: | |
| 183 | + pci_iounmap(pdev, csr); | |
| 184 | + err_release_reg: | |
| 185 | + pci_release_region(pdev, 0); | |
| 186 | + err_disable_pdev: | |
| 187 | + pci_disable_device(pdev); | |
| 188 | + | |
| 189 | + return rc; | |
| 190 | +} | |
| 191 | + | |
| 192 | +static void wil_pcie_remove(struct pci_dev *pdev) | |
| 193 | +{ | |
| 194 | + struct wil6210_priv *wil = pci_get_drvdata(pdev); | |
| 195 | + | |
| 196 | + wil6210_debugfs_remove(wil); | |
| 197 | + wil_if_pcie_disable(wil); | |
| 198 | + wil_if_remove(wil); | |
| 199 | + wil_if_free(wil); | |
| 200 | + pci_iounmap(pdev, wil->csr); | |
| 201 | + pci_release_region(pdev, 0); | |
| 202 | + pci_disable_device(pdev); | |
| 203 | + pci_set_drvdata(pdev, NULL); | |
| 204 | +} | |
| 205 | + | |
| 206 | +static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = { | |
| 207 | + { PCI_DEVICE(0x1ae9, 0x0301) }, | |
| 208 | + { /* end: all zeroes */ }, | |
| 209 | +}; | |
| 210 | +MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); | |
| 211 | + | |
| 212 | +static struct pci_driver wil6210_driver = { | |
| 213 | + .probe = wil_pcie_probe, | |
| 214 | + .remove = wil_pcie_remove, | |
| 215 | + .id_table = wil6210_pcie_ids, | |
| 216 | + .name = WIL_NAME, | |
| 217 | +}; | |
| 218 | + | |
| 219 | +module_pci_driver(wil6210_driver); | |
| 220 | + | |
| 221 | +MODULE_LICENSE("Dual BSD/GPL"); | |
| 222 | +MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>"); | |
| 223 | +MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card"); | |
| @@ -0,0 +1,871 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 11 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 13 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 14 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/kernel.h> | |
| 18 | +#include <linux/netdevice.h> | |
| 19 | +#include <linux/etherdevice.h> | |
| 20 | +#include <linux/hardirq.h> | |
| 21 | +#include <net/ieee80211_radiotap.h> | |
| 22 | +#include <linux/if_arp.h> | |
| 23 | +#include <linux/moduleparam.h> | |
| 24 | + | |
| 25 | +#include "wil6210.h" | |
| 26 | +#include "wmi.h" | |
| 27 | +#include "txrx.h" | |
| 28 | + | |
| 29 | +static bool rtap_include_phy_info; | |
| 30 | +module_param(rtap_include_phy_info, bool, S_IRUGO); | |
| 31 | +MODULE_PARM_DESC(rtap_include_phy_info, | |
| 32 | + " Include PHY info in the radiotap header, default - no"); | |
| 33 | + | |
| 34 | +static inline int wil_vring_is_empty(struct vring *vring) | |
| 35 | +{ | |
| 36 | + return vring->swhead == vring->swtail; | |
| 37 | +} | |
| 38 | + | |
| 39 | +static inline u32 wil_vring_next_tail(struct vring *vring) | |
| 40 | +{ | |
| 41 | + return (vring->swtail + 1) % vring->size; | |
| 42 | +} | |
| 43 | + | |
| 44 | +static inline void wil_vring_advance_head(struct vring *vring, int n) | |
| 45 | +{ | |
| 46 | + vring->swhead = (vring->swhead + n) % vring->size; | |
| 47 | +} | |
| 48 | + | |
| 49 | +static inline int wil_vring_is_full(struct vring *vring) | |
| 50 | +{ | |
| 51 | + return wil_vring_next_tail(vring) == vring->swhead; | |
| 52 | +} | |
| 53 | +/* | |
| 54 | + * Available space in Tx Vring | |
| 55 | + */ | |
| 56 | +static inline int wil_vring_avail_tx(struct vring *vring) | |
| 57 | +{ | |
| 58 | + u32 swhead = vring->swhead; | |
| 59 | + u32 swtail = vring->swtail; | |
| 60 | + int used = (vring->size + swhead - swtail) % vring->size; | |
| 61 | + | |
| 62 | + return vring->size - used - 1; | |
| 63 | +} | |
| 64 | + | |
| 65 | +static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) | |
| 66 | +{ | |
| 67 | + struct device *dev = wil_to_dev(wil); | |
| 68 | + size_t sz = vring->size * sizeof(vring->va[0]); | |
| 69 | + uint i; | |
| 70 | + | |
| 71 | + BUILD_BUG_ON(sizeof(vring->va[0]) != 32); | |
| 72 | + | |
| 73 | + vring->swhead = 0; | |
| 74 | + vring->swtail = 0; | |
| 75 | + vring->ctx = kzalloc(vring->size * sizeof(vring->ctx[0]), GFP_KERNEL); | |
| 76 | + if (!vring->ctx) { | |
| 77 | + wil_err(wil, "vring_alloc [%d] failed to alloc ctx mem\n", | |
| 78 | + vring->size); | |
| 79 | + vring->va = NULL; | |
| 80 | + return -ENOMEM; | |
| 81 | + } | |
| 82 | + /* | |
| 83 | + * vring->va should be aligned on its size rounded up to power of 2 | |
| 84 | + * This is granted by the dma_alloc_coherent | |
| 85 | + */ | |
| 86 | + vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL); | |
| 87 | + if (!vring->va) { | |
| 88 | + wil_err(wil, "vring_alloc [%d] failed to alloc DMA mem\n", | |
| 89 | + vring->size); | |
| 90 | + kfree(vring->ctx); | |
| 91 | + vring->ctx = NULL; | |
| 92 | + return -ENOMEM; | |
| 93 | + } | |
| 94 | + /* initially, all descriptors are SW owned | |
| 95 | + * For Tx and Rx, ownership bit is at the same location, thus | |
| 96 | + * we can use any | |
| 97 | + */ | |
| 98 | + for (i = 0; i < vring->size; i++) { | |
| 99 | + volatile struct vring_tx_desc *d = &(vring->va[i].tx); | |
| 100 | + d->dma.status = TX_DMA_STATUS_DU; | |
| 101 | + } | |
| 102 | + | |
| 103 | + wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, | |
| 104 | + vring->va, (unsigned long long)vring->pa, vring->ctx); | |
| 105 | + | |
| 106 | + return 0; | |
| 107 | +} | |
| 108 | + | |
| 109 | +static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, | |
| 110 | + int tx) | |
| 111 | +{ | |
| 112 | + struct device *dev = wil_to_dev(wil); | |
| 113 | + size_t sz = vring->size * sizeof(vring->va[0]); | |
| 114 | + | |
| 115 | + while (!wil_vring_is_empty(vring)) { | |
| 116 | + if (tx) { | |
| 117 | + volatile struct vring_tx_desc *d = | |
| 118 | + &vring->va[vring->swtail].tx; | |
| 119 | + dma_addr_t pa = d->dma.addr_low | | |
| 120 | + ((u64)d->dma.addr_high << 32); | |
| 121 | + struct sk_buff *skb = vring->ctx[vring->swtail]; | |
| 122 | + if (skb) { | |
| 123 | + dma_unmap_single(dev, pa, d->dma.length, | |
| 124 | + DMA_TO_DEVICE); | |
| 125 | + dev_kfree_skb_any(skb); | |
| 126 | + vring->ctx[vring->swtail] = NULL; | |
| 127 | + } else { | |
| 128 | + dma_unmap_page(dev, pa, d->dma.length, | |
| 129 | + DMA_TO_DEVICE); | |
| 130 | + } | |
| 131 | + vring->swtail = wil_vring_next_tail(vring); | |
| 132 | + } else { /* rx */ | |
| 133 | + volatile struct vring_rx_desc *d = | |
| 134 | + &vring->va[vring->swtail].rx; | |
| 135 | + dma_addr_t pa = d->dma.addr_low | | |
| 136 | + ((u64)d->dma.addr_high << 32); | |
| 137 | + struct sk_buff *skb = vring->ctx[vring->swhead]; | |
| 138 | + dma_unmap_single(dev, pa, d->dma.length, | |
| 139 | + DMA_FROM_DEVICE); | |
| 140 | + kfree_skb(skb); | |
| 141 | + wil_vring_advance_head(vring, 1); | |
| 142 | + } | |
| 143 | + } | |
| 144 | + dma_free_coherent(dev, sz, (void *)vring->va, vring->pa); | |
| 145 | + kfree(vring->ctx); | |
| 146 | + vring->pa = 0; | |
| 147 | + vring->va = NULL; | |
| 148 | + vring->ctx = NULL; | |
| 149 | +} | |
| 150 | + | |
| 151 | +/** | |
| 152 | + * Allocate one skb for Rx VRING | |
| 153 | + * | |
| 154 | + * Safe to call from IRQ | |
| 155 | + */ | |
| 156 | +static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, | |
| 157 | + u32 i, int headroom) | |
| 158 | +{ | |
| 159 | + struct device *dev = wil_to_dev(wil); | |
| 160 | + unsigned int sz = RX_BUF_LEN; | |
| 161 | + volatile struct vring_rx_desc *d = &(vring->va[i].rx); | |
| 162 | + dma_addr_t pa; | |
| 163 | + | |
| 164 | + /* TODO align */ | |
| 165 | + struct sk_buff *skb = dev_alloc_skb(sz + headroom); | |
| 166 | + if (unlikely(!skb)) | |
| 167 | + return -ENOMEM; | |
| 168 | + | |
| 169 | + skb_reserve(skb, headroom); | |
| 170 | + skb_put(skb, sz); | |
| 171 | + | |
| 172 | + pa = dma_map_single(dev, skb->data, skb->len, DMA_FROM_DEVICE); | |
| 173 | + if (unlikely(dma_mapping_error(dev, pa))) { | |
| 174 | + kfree_skb(skb); | |
| 175 | + return -ENOMEM; | |
| 176 | + } | |
| 177 | + | |
| 178 | + d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT; | |
| 179 | + d->dma.addr_low = lower_32_bits(pa); | |
| 180 | + d->dma.addr_high = (u16)upper_32_bits(pa); | |
| 181 | + /* ip_length don't care */ | |
| 182 | + /* b11 don't care */ | |
| 183 | + /* error don't care */ | |
| 184 | + d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ | |
| 185 | + d->dma.length = sz; | |
| 186 | + vring->ctx[i] = skb; | |
| 187 | + | |
| 188 | + return 0; | |
| 189 | +} | |
| 190 | + | |
| 191 | +/** | |
| 192 | + * Adds radiotap header | |
| 193 | + * | |
| 194 | + * Any error indicated as "Bad FCS" | |
| 195 | + * | |
| 196 | + * Vendor data for 04:ce:14-1 (Wilocity-1) consists of: | |
| 197 | + * - Rx descriptor: 32 bytes | |
| 198 | + * - Phy info | |
| 199 | + */ | |
| 200 | +static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, | |
| 201 | + struct sk_buff *skb, | |
| 202 | + volatile struct vring_rx_desc *d) | |
| 203 | +{ | |
| 204 | + struct wireless_dev *wdev = wil->wdev; | |
| 205 | + struct wil6210_rtap { | |
| 206 | + struct ieee80211_radiotap_header rthdr; | |
| 207 | + /* fields should be in the order of bits in rthdr.it_present */ | |
| 208 | + /* flags */ | |
| 209 | + u8 flags; | |
| 210 | + /* channel */ | |
| 211 | + __le16 chnl_freq __aligned(2); | |
| 212 | + __le16 chnl_flags; | |
| 213 | + /* MCS */ | |
| 214 | + u8 mcs_present; | |
| 215 | + u8 mcs_flags; | |
| 216 | + u8 mcs_index; | |
| 217 | + } __packed; | |
| 218 | + struct wil6210_rtap_vendor { | |
| 219 | + struct wil6210_rtap rtap; | |
| 220 | + /* vendor */ | |
| 221 | + u8 vendor_oui[3] __aligned(2); | |
| 222 | + u8 vendor_ns; | |
| 223 | + __le16 vendor_skip; | |
| 224 | + u8 vendor_data[0]; | |
| 225 | + } __packed; | |
| 226 | + struct wil6210_rtap_vendor *rtap_vendor; | |
| 227 | + int rtap_len = sizeof(struct wil6210_rtap); | |
| 228 | + int phy_length = 0; /* phy info header size, bytes */ | |
| 229 | + static char phy_data[128]; | |
| 230 | + struct ieee80211_channel *ch = wdev->preset_chandef.chan; | |
| 231 | + | |
| 232 | + if (rtap_include_phy_info) { | |
| 233 | + rtap_len = sizeof(*rtap_vendor) + sizeof(*d); | |
| 234 | + /* calculate additional length */ | |
| 235 | + if (d->dma.status & RX_DMA_STATUS_PHY_INFO) { | |
| 236 | + /** | |
| 237 | + * PHY info starts from 8-byte boundary | |
| 238 | + * there are 8-byte lines, last line may be partially | |
| 239 | + * written (HW bug), thus FW configures for last line | |
| 240 | + * to be excessive. Driver skips this last line. | |
| 241 | + */ | |
| 242 | + int len = min_t(int, 8 + sizeof(phy_data), | |
| 243 | + wil_rxdesc_phy_length(d)); | |
| 244 | + if (len > 8) { | |
| 245 | + void *p = skb_tail_pointer(skb); | |
| 246 | + void *pa = PTR_ALIGN(p, 8); | |
| 247 | + if (skb_tailroom(skb) >= len + (pa - p)) { | |
| 248 | + phy_length = len - 8; | |
| 249 | + memcpy(phy_data, pa, phy_length); | |
| 250 | + } | |
| 251 | + } | |
| 252 | + } | |
| 253 | + rtap_len += phy_length; | |
| 254 | + } | |
| 255 | + | |
| 256 | + if (skb_headroom(skb) < rtap_len && | |
| 257 | + pskb_expand_head(skb, rtap_len, 0, GFP_ATOMIC)) { | |
| 258 | + wil_err(wil, "Unable to expand headrom to %d\n", rtap_len); | |
| 259 | + return; | |
| 260 | + } | |
| 261 | + | |
| 262 | + rtap_vendor = (void *)skb_push(skb, rtap_len); | |
| 263 | + memset(rtap_vendor, 0, rtap_len); | |
| 264 | + | |
| 265 | + rtap_vendor->rtap.rthdr.it_version = PKTHDR_RADIOTAP_VERSION; | |
| 266 | + rtap_vendor->rtap.rthdr.it_len = cpu_to_le16(rtap_len); | |
| 267 | + rtap_vendor->rtap.rthdr.it_present = cpu_to_le32( | |
| 268 | + (1 << IEEE80211_RADIOTAP_FLAGS) | | |
| 269 | + (1 << IEEE80211_RADIOTAP_CHANNEL) | | |
| 270 | + (1 << IEEE80211_RADIOTAP_MCS)); | |
| 271 | + if (d->dma.status & RX_DMA_STATUS_ERROR) | |
| 272 | + rtap_vendor->rtap.flags |= IEEE80211_RADIOTAP_F_BADFCS; | |
| 273 | + | |
| 274 | + rtap_vendor->rtap.chnl_freq = cpu_to_le16(ch ? ch->center_freq : 58320); | |
| 275 | + rtap_vendor->rtap.chnl_flags = cpu_to_le16(0); | |
| 276 | + | |
| 277 | + rtap_vendor->rtap.mcs_present = IEEE80211_RADIOTAP_MCS_HAVE_MCS; | |
| 278 | + rtap_vendor->rtap.mcs_flags = 0; | |
| 279 | + rtap_vendor->rtap.mcs_index = wil_rxdesc_mcs(d); | |
| 280 | + | |
| 281 | + if (rtap_include_phy_info) { | |
| 282 | + rtap_vendor->rtap.rthdr.it_present |= cpu_to_le32(1 << | |
| 283 | + IEEE80211_RADIOTAP_VENDOR_NAMESPACE); | |
| 284 | + /* OUI for Wilocity 04:ce:14 */ | |
| 285 | + rtap_vendor->vendor_oui[0] = 0x04; | |
| 286 | + rtap_vendor->vendor_oui[1] = 0xce; | |
| 287 | + rtap_vendor->vendor_oui[2] = 0x14; | |
| 288 | + rtap_vendor->vendor_ns = 1; | |
| 289 | + /* Rx descriptor + PHY data */ | |
| 290 | + rtap_vendor->vendor_skip = cpu_to_le16(sizeof(*d) + | |
| 291 | + phy_length); | |
| 292 | + memcpy(rtap_vendor->vendor_data, (void *)d, sizeof(*d)); | |
| 293 | + memcpy(rtap_vendor->vendor_data + sizeof(*d), phy_data, | |
| 294 | + phy_length); | |
| 295 | + } | |
| 296 | +} | |
| 297 | + | |
| 298 | +/* | |
| 299 | + * Fast swap in place between 2 registers | |
| 300 | + */ | |
| 301 | +static void wil_swap_u16(u16 *a, u16 *b) | |
| 302 | +{ | |
| 303 | + *a ^= *b; | |
| 304 | + *b ^= *a; | |
| 305 | + *a ^= *b; | |
| 306 | +} | |
| 307 | + | |
| 308 | +static void wil_swap_ethaddr(void *data) | |
| 309 | +{ | |
| 310 | + struct ethhdr *eth = data; | |
| 311 | + u16 *s = (u16 *)eth->h_source; | |
| 312 | + u16 *d = (u16 *)eth->h_dest; | |
| 313 | + | |
| 314 | + wil_swap_u16(s++, d++); | |
| 315 | + wil_swap_u16(s++, d++); | |
| 316 | + wil_swap_u16(s, d); | |
| 317 | +} | |
| 318 | + | |
| 319 | +/** | |
| 320 | + * reap 1 frame from @swhead | |
| 321 | + * | |
| 322 | + * Safe to call from IRQ | |
| 323 | + */ | |
| 324 | +static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |
| 325 | + struct vring *vring) | |
| 326 | +{ | |
| 327 | + struct device *dev = wil_to_dev(wil); | |
| 328 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 329 | + volatile struct vring_rx_desc *d; | |
| 330 | + struct sk_buff *skb; | |
| 331 | + dma_addr_t pa; | |
| 332 | + unsigned int sz = RX_BUF_LEN; | |
| 333 | + u8 ftype; | |
| 334 | + u8 ds_bits; | |
| 335 | + | |
| 336 | + if (wil_vring_is_empty(vring)) | |
| 337 | + return NULL; | |
| 338 | + | |
| 339 | + d = &(vring->va[vring->swhead].rx); | |
| 340 | + if (!(d->dma.status & RX_DMA_STATUS_DU)) { | |
| 341 | + /* it is not error, we just reached end of Rx done area */ | |
| 342 | + return NULL; | |
| 343 | + } | |
| 344 | + | |
| 345 | + pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | |
| 346 | + skb = vring->ctx[vring->swhead]; | |
| 347 | + dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); | |
| 348 | + skb_trim(skb, d->dma.length); | |
| 349 | + | |
| 350 | + wil->stats.last_mcs_rx = wil_rxdesc_mcs(d); | |
| 351 | + | |
| 352 | + /* use radiotap header only if required */ | |
| 353 | + if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) | |
| 354 | + wil_rx_add_radiotap_header(wil, skb, d); | |
| 355 | + | |
| 356 | + wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length); | |
| 357 | + wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4, | |
| 358 | + (const void *)d, sizeof(*d), false); | |
| 359 | + | |
| 360 | + wil_vring_advance_head(vring, 1); | |
| 361 | + | |
| 362 | + /* no extra checks if in sniffer mode */ | |
| 363 | + if (ndev->type != ARPHRD_ETHER) | |
| 364 | + return skb; | |
| 365 | + /* | |
| 366 | + * Non-data frames may be delivered through Rx DMA channel (ex: BAR) | |
| 367 | + * Driver should recognize it by frame type, that is found | |
| 368 | + * in Rx descriptor. If type is not data, it is 802.11 frame as is | |
| 369 | + */ | |
| 370 | + ftype = wil_rxdesc_ftype(d) << 2; | |
| 371 | + if (ftype != IEEE80211_FTYPE_DATA) { | |
| 372 | + wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype); | |
| 373 | + /* TODO: process it */ | |
| 374 | + kfree_skb(skb); | |
| 375 | + return NULL; | |
| 376 | + } | |
| 377 | + | |
| 378 | + if (skb->len < ETH_HLEN) { | |
| 379 | + wil_err(wil, "Short frame, len = %d\n", skb->len); | |
| 380 | + /* TODO: process it (i.e. BAR) */ | |
| 381 | + kfree_skb(skb); | |
| 382 | + return NULL; | |
| 383 | + } | |
| 384 | + | |
| 385 | + ds_bits = wil_rxdesc_ds_bits(d); | |
| 386 | + if (ds_bits == 1) { | |
| 387 | + /* | |
| 388 | + * HW bug - in ToDS mode, i.e. Rx on AP side, | |
| 389 | + * addresses get swapped | |
| 390 | + */ | |
| 391 | + wil_swap_ethaddr(skb->data); | |
| 392 | + } | |
| 393 | + | |
| 394 | + return skb; | |
| 395 | +} | |
| 396 | + | |
| 397 | +/** | |
| 398 | + * allocate and fill up to @count buffers in rx ring | |
| 399 | + * buffers posted at @swtail | |
| 400 | + */ | |
| 401 | +static int wil_rx_refill(struct wil6210_priv *wil, int count) | |
| 402 | +{ | |
| 403 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 404 | + struct vring *v = &wil->vring_rx; | |
| 405 | + u32 next_tail; | |
| 406 | + int rc = 0; | |
| 407 | + int headroom = ndev->type == ARPHRD_IEEE80211_RADIOTAP ? | |
| 408 | + WIL6210_RTAP_SIZE : 0; | |
| 409 | + | |
| 410 | + for (; next_tail = wil_vring_next_tail(v), | |
| 411 | + (next_tail != v->swhead) && (count-- > 0); | |
| 412 | + v->swtail = next_tail) { | |
| 413 | + rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom); | |
| 414 | + if (rc) { | |
| 415 | + wil_err(wil, "Error %d in wil_rx_refill[%d]\n", | |
| 416 | + rc, v->swtail); | |
| 417 | + break; | |
| 418 | + } | |
| 419 | + } | |
| 420 | + iowrite32(v->swtail, wil->csr + HOSTADDR(v->hwtail)); | |
| 421 | + | |
| 422 | + return rc; | |
| 423 | +} | |
| 424 | + | |
| 425 | +/* | |
| 426 | + * Pass Rx packet to the netif. Update statistics. | |
| 427 | + */ | |
| 428 | +static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) | |
| 429 | +{ | |
| 430 | + int rc; | |
| 431 | + unsigned int len = skb->len; | |
| 432 | + | |
| 433 | + if (in_interrupt()) | |
| 434 | + rc = netif_rx(skb); | |
| 435 | + else | |
| 436 | + rc = netif_rx_ni(skb); | |
| 437 | + | |
| 438 | + if (likely(rc == NET_RX_SUCCESS)) { | |
| 439 | + ndev->stats.rx_packets++; | |
| 440 | + ndev->stats.rx_bytes += len; | |
| 441 | + | |
| 442 | + } else { | |
| 443 | + ndev->stats.rx_dropped++; | |
| 444 | + } | |
| 445 | +} | |
| 446 | + | |
| 447 | +/** | |
| 448 | + * Proceed all completed skb's from Rx VRING | |
| 449 | + * | |
| 450 | + * Safe to call from IRQ | |
| 451 | + */ | |
| 452 | +void wil_rx_handle(struct wil6210_priv *wil) | |
| 453 | +{ | |
| 454 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 455 | + struct vring *v = &wil->vring_rx; | |
| 456 | + struct sk_buff *skb; | |
| 457 | + | |
| 458 | + if (!v->va) { | |
| 459 | + wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); | |
| 460 | + return; | |
| 461 | + } | |
| 462 | + wil_dbg_TXRX(wil, "%s()\n", __func__); | |
| 463 | + while (NULL != (skb = wil_vring_reap_rx(wil, v))) { | |
| 464 | + wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1, | |
| 465 | + skb->data, skb_headlen(skb), false); | |
| 466 | + | |
| 467 | + skb_orphan(skb); | |
| 468 | + | |
| 469 | + if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { | |
| 470 | + skb->dev = ndev; | |
| 471 | + skb_reset_mac_header(skb); | |
| 472 | + skb->ip_summed = CHECKSUM_UNNECESSARY; | |
| 473 | + skb->pkt_type = PACKET_OTHERHOST; | |
| 474 | + skb->protocol = htons(ETH_P_802_2); | |
| 475 | + | |
| 476 | + } else { | |
| 477 | + skb->protocol = eth_type_trans(skb, ndev); | |
| 478 | + } | |
| 479 | + | |
| 480 | + wil_netif_rx_any(skb, ndev); | |
| 481 | + } | |
| 482 | + wil_rx_refill(wil, v->size); | |
| 483 | +} | |
| 484 | + | |
| 485 | +int wil_rx_init(struct wil6210_priv *wil) | |
| 486 | +{ | |
| 487 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 488 | + struct wireless_dev *wdev = wil->wdev; | |
| 489 | + struct vring *vring = &wil->vring_rx; | |
| 490 | + int rc; | |
| 491 | + struct wmi_cfg_rx_chain_cmd cmd = { | |
| 492 | + .action = WMI_RX_CHAIN_ADD, | |
| 493 | + .rx_sw_ring = { | |
| 494 | + .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), | |
| 495 | + }, | |
| 496 | + .mid = 0, /* TODO - what is it? */ | |
| 497 | + .decap_trans_type = WMI_DECAP_TYPE_802_3, | |
| 498 | + }; | |
| 499 | + struct { | |
| 500 | + struct wil6210_mbox_hdr_wmi wmi; | |
| 501 | + struct wmi_cfg_rx_chain_done_event evt; | |
| 502 | + } __packed evt; | |
| 503 | + | |
| 504 | + vring->size = WIL6210_RX_RING_SIZE; | |
| 505 | + rc = wil_vring_alloc(wil, vring); | |
| 506 | + if (rc) | |
| 507 | + return rc; | |
| 508 | + | |
| 509 | + cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); | |
| 510 | + cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size); | |
| 511 | + if (wdev->iftype == NL80211_IFTYPE_MONITOR) { | |
| 512 | + struct ieee80211_channel *ch = wdev->preset_chandef.chan; | |
| 513 | + | |
| 514 | + cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON); | |
| 515 | + if (ch) | |
| 516 | + cmd.sniffer_cfg.channel = ch->hw_value - 1; | |
| 517 | + cmd.sniffer_cfg.phy_info_mode = | |
| 518 | + cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); | |
| 519 | + cmd.sniffer_cfg.phy_support = | |
| 520 | + cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) | |
| 521 | + ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); | |
| 522 | + } | |
| 523 | + /* typical time for secure PCP is 840ms */ | |
| 524 | + rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), | |
| 525 | + WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); | |
| 526 | + if (rc) | |
| 527 | + goto err_free; | |
| 528 | + | |
| 529 | + vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr); | |
| 530 | + | |
| 531 | + wil_dbg(wil, "Rx init: status %d tail 0x%08x\n", | |
| 532 | + le32_to_cpu(evt.evt.status), vring->hwtail); | |
| 533 | + | |
| 534 | + rc = wil_rx_refill(wil, vring->size); | |
| 535 | + if (rc) | |
| 536 | + goto err_free; | |
| 537 | + | |
| 538 | + return 0; | |
| 539 | + err_free: | |
| 540 | + wil_vring_free(wil, vring, 0); | |
| 541 | + | |
| 542 | + return rc; | |
| 543 | +} | |
| 544 | + | |
| 545 | +void wil_rx_fini(struct wil6210_priv *wil) | |
| 546 | +{ | |
| 547 | + struct vring *vring = &wil->vring_rx; | |
| 548 | + | |
| 549 | + if (vring->va) { | |
| 550 | + int rc; | |
| 551 | + struct wmi_cfg_rx_chain_cmd cmd = { | |
| 552 | + .action = cpu_to_le32(WMI_RX_CHAIN_DEL), | |
| 553 | + .rx_sw_ring = { | |
| 554 | + .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), | |
| 555 | + }, | |
| 556 | + }; | |
| 557 | + struct { | |
| 558 | + struct wil6210_mbox_hdr_wmi wmi; | |
| 559 | + struct wmi_cfg_rx_chain_done_event cfg; | |
| 560 | + } __packed wmi_rx_cfg_reply; | |
| 561 | + | |
| 562 | + rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), | |
| 563 | + WMI_CFG_RX_CHAIN_DONE_EVENTID, | |
| 564 | + &wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply), | |
| 565 | + 100); | |
| 566 | + wil_vring_free(wil, vring, 0); | |
| 567 | + } | |
| 568 | +} | |
| 569 | + | |
| 570 | +int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | |
| 571 | + int cid, int tid) | |
| 572 | +{ | |
| 573 | + int rc; | |
| 574 | + struct wmi_vring_cfg_cmd cmd = { | |
| 575 | + .action = cpu_to_le32(WMI_VRING_CMD_ADD), | |
| 576 | + .vring_cfg = { | |
| 577 | + .tx_sw_ring = { | |
| 578 | + .max_mpdu_size = cpu_to_le16(TX_BUF_LEN), | |
| 579 | + }, | |
| 580 | + .ringid = id, | |
| 581 | + .cidxtid = (cid & 0xf) | ((tid & 0xf) << 4), | |
| 582 | + .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, | |
| 583 | + .mac_ctrl = 0, | |
| 584 | + .to_resolution = 0, | |
| 585 | + .agg_max_wsize = 16, | |
| 586 | + .schd_params = { | |
| 587 | + .priority = cpu_to_le16(0), | |
| 588 | + .timeslot_us = cpu_to_le16(0xfff), | |
| 589 | + }, | |
| 590 | + }, | |
| 591 | + }; | |
| 592 | + struct { | |
| 593 | + struct wil6210_mbox_hdr_wmi wmi; | |
| 594 | + struct wmi_vring_cfg_done_event cmd; | |
| 595 | + } __packed reply; | |
| 596 | + struct vring *vring = &wil->vring_tx[id]; | |
| 597 | + | |
| 598 | + if (vring->va) { | |
| 599 | + wil_err(wil, "Tx ring [%d] already allocated\n", id); | |
| 600 | + rc = -EINVAL; | |
| 601 | + goto out; | |
| 602 | + } | |
| 603 | + | |
| 604 | + vring->size = size; | |
| 605 | + rc = wil_vring_alloc(wil, vring); | |
| 606 | + if (rc) | |
| 607 | + goto out; | |
| 608 | + | |
| 609 | + cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); | |
| 610 | + cmd.vring_cfg.tx_sw_ring.ring_size = cpu_to_le16(vring->size); | |
| 611 | + | |
| 612 | + rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd), | |
| 613 | + WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); | |
| 614 | + if (rc) | |
| 615 | + goto out_free; | |
| 616 | + | |
| 617 | + if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) { | |
| 618 | + wil_err(wil, "Tx config failed, status 0x%02x\n", | |
| 619 | + reply.cmd.status); | |
| 620 | + goto out_free; | |
| 621 | + } | |
| 622 | + vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); | |
| 623 | + | |
| 624 | + return 0; | |
| 625 | + out_free: | |
| 626 | + wil_vring_free(wil, vring, 1); | |
| 627 | + out: | |
| 628 | + | |
| 629 | + return rc; | |
| 630 | +} | |
| 631 | + | |
| 632 | +void wil_vring_fini_tx(struct wil6210_priv *wil, int id) | |
| 633 | +{ | |
| 634 | + struct vring *vring = &wil->vring_tx[id]; | |
| 635 | + | |
| 636 | + if (!vring->va) | |
| 637 | + return; | |
| 638 | + | |
| 639 | + wil_vring_free(wil, vring, 1); | |
| 640 | +} | |
| 641 | + | |
| 642 | +static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, | |
| 643 | + struct sk_buff *skb) | |
| 644 | +{ | |
| 645 | + struct vring *v = &wil->vring_tx[0]; | |
| 646 | + | |
| 647 | + if (v->va) | |
| 648 | + return v; | |
| 649 | + | |
| 650 | + return NULL; | |
| 651 | +} | |
| 652 | + | |
| 653 | +static int wil_tx_desc_map(volatile struct vring_tx_desc *d, | |
| 654 | + dma_addr_t pa, u32 len) | |
| 655 | +{ | |
| 656 | + d->dma.addr_low = lower_32_bits(pa); | |
| 657 | + d->dma.addr_high = (u16)upper_32_bits(pa); | |
| 658 | + d->dma.ip_length = 0; | |
| 659 | + /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/ | |
| 660 | + d->dma.b11 = 0/*14 | BIT(7)*/; | |
| 661 | + d->dma.error = 0; | |
| 662 | + d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ | |
| 663 | + d->dma.length = len; | |
| 664 | + d->dma.d0 = 0; | |
| 665 | + d->mac.d[0] = 0; | |
| 666 | + d->mac.d[1] = 0; | |
| 667 | + d->mac.d[2] = 0; | |
| 668 | + d->mac.ucode_cmd = 0; | |
| 669 | + /* use dst index 0 */ | |
| 670 | + d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) | | |
| 671 | + (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS); | |
| 672 | + /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ | |
| 673 | + d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | | |
| 674 | + (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); | |
| 675 | + | |
| 676 | + return 0; | |
| 677 | +} | |
| 678 | + | |
| 679 | +static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |
| 680 | + struct sk_buff *skb) | |
| 681 | +{ | |
| 682 | + struct device *dev = wil_to_dev(wil); | |
| 683 | + volatile struct vring_tx_desc *d; | |
| 684 | + u32 swhead = vring->swhead; | |
| 685 | + int avail = wil_vring_avail_tx(vring); | |
| 686 | + int nr_frags = skb_shinfo(skb)->nr_frags; | |
| 687 | + uint f; | |
| 688 | + int vring_index = vring - wil->vring_tx; | |
| 689 | + uint i = swhead; | |
| 690 | + dma_addr_t pa; | |
| 691 | + | |
| 692 | + wil_dbg_TXRX(wil, "%s()\n", __func__); | |
| 693 | + | |
| 694 | + if (avail < vring->size/8) | |
| 695 | + netif_tx_stop_all_queues(wil_to_ndev(wil)); | |
| 696 | + if (avail < 1 + nr_frags) { | |
| 697 | + wil_err(wil, "Tx ring full. No space for %d fragments\n", | |
| 698 | + 1 + nr_frags); | |
| 699 | + return -ENOMEM; | |
| 700 | + } | |
| 701 | + d = &(vring->va[i].tx); | |
| 702 | + | |
| 703 | + /* FIXME FW can accept only unicast frames for the peer */ | |
| 704 | + memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN); | |
| 705 | + | |
| 706 | + pa = dma_map_single(dev, skb->data, | |
| 707 | + skb_headlen(skb), DMA_TO_DEVICE); | |
| 708 | + | |
| 709 | + wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), | |
| 710 | + skb->data, (unsigned long long)pa); | |
| 711 | + wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1, | |
| 712 | + skb->data, skb_headlen(skb), false); | |
| 713 | + | |
| 714 | + if (unlikely(dma_mapping_error(dev, pa))) | |
| 715 | + return -EINVAL; | |
| 716 | + /* 1-st segment */ | |
| 717 | + wil_tx_desc_map(d, pa, skb_headlen(skb)); | |
| 718 | + d->mac.d[2] |= ((nr_frags + 1) << | |
| 719 | + MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); | |
| 720 | + /* middle segments */ | |
| 721 | + for (f = 0; f < nr_frags; f++) { | |
| 722 | + const struct skb_frag_struct *frag = | |
| 723 | + &skb_shinfo(skb)->frags[f]; | |
| 724 | + int len = skb_frag_size(frag); | |
| 725 | + i = (swhead + f + 1) % vring->size; | |
| 726 | + d = &(vring->va[i].tx); | |
| 727 | + pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), | |
| 728 | + DMA_TO_DEVICE); | |
| 729 | + if (unlikely(dma_mapping_error(dev, pa))) | |
| 730 | + goto dma_error; | |
| 731 | + wil_tx_desc_map(d, pa, len); | |
| 732 | + vring->ctx[i] = NULL; | |
| 733 | + } | |
| 734 | + /* for the last seg only */ | |
| 735 | + d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); | |
| 736 | + d->dma.d0 |= BIT(9); /* BUG: undocumented bit */ | |
| 737 | + d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); | |
| 738 | + d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS); | |
| 739 | + | |
| 740 | + wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4, | |
| 741 | + (const void *)d, sizeof(*d), false); | |
| 742 | + | |
| 743 | + /* advance swhead */ | |
| 744 | + wil_vring_advance_head(vring, nr_frags + 1); | |
| 745 | + wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); | |
| 746 | + iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); | |
| 747 | + /* hold reference to skb | |
| 748 | + * to prevent skb release before accounting | |
| 749 | + * in case of immediate "tx done" | |
| 750 | + */ | |
| 751 | + vring->ctx[i] = skb_get(skb); | |
| 752 | + | |
| 753 | + return 0; | |
| 754 | + dma_error: | |
| 755 | + /* unmap what we have mapped */ | |
| 756 | + /* Note: increment @f to operate with positive index */ | |
| 757 | + for (f++; f > 0; f--) { | |
| 758 | + i = (swhead + f) % vring->size; | |
| 759 | + d = &(vring->va[i].tx); | |
| 760 | + d->dma.status = TX_DMA_STATUS_DU; | |
| 761 | + pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | |
| 762 | + if (vring->ctx[i]) | |
| 763 | + dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); | |
| 764 | + else | |
| 765 | + dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE); | |
| 766 | + } | |
| 767 | + | |
| 768 | + return -EINVAL; | |
| 769 | +} | |
| 770 | + | |
| 771 | + | |
| 772 | +netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |
| 773 | +{ | |
| 774 | + struct wil6210_priv *wil = ndev_to_wil(ndev); | |
| 775 | + struct vring *vring; | |
| 776 | + int rc; | |
| 777 | + | |
| 778 | + wil_dbg_TXRX(wil, "%s()\n", __func__); | |
| 779 | + if (!test_bit(wil_status_fwready, &wil->status)) { | |
| 780 | + wil_err(wil, "FW not ready\n"); | |
| 781 | + goto drop; | |
| 782 | + } | |
| 783 | + if (!test_bit(wil_status_fwconnected, &wil->status)) { | |
| 784 | + wil_err(wil, "FW not connected\n"); | |
| 785 | + goto drop; | |
| 786 | + } | |
| 787 | + if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { | |
| 788 | + wil_err(wil, "Xmit in monitor mode not supported\n"); | |
| 789 | + goto drop; | |
| 790 | + } | |
| 791 | + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { | |
| 792 | + rc = wmi_tx_eapol(wil, skb); | |
| 793 | + } else { | |
| 794 | + /* find vring */ | |
| 795 | + vring = wil_find_tx_vring(wil, skb); | |
| 796 | + if (!vring) { | |
| 797 | + wil_err(wil, "No Tx VRING available\n"); | |
| 798 | + goto drop; | |
| 799 | + } | |
| 800 | + /* set up vring entry */ | |
| 801 | + rc = wil_tx_vring(wil, vring, skb); | |
| 802 | + } | |
| 803 | + switch (rc) { | |
| 804 | + case 0: | |
| 805 | + ndev->stats.tx_packets++; | |
| 806 | + ndev->stats.tx_bytes += skb->len; | |
| 807 | + dev_kfree_skb_any(skb); | |
| 808 | + return NETDEV_TX_OK; | |
| 809 | + case -ENOMEM: | |
| 810 | + return NETDEV_TX_BUSY; | |
| 811 | + default: | |
| 812 | + ; /* goto drop; */ | |
| 813 | + break; | |
| 814 | + } | |
| 815 | + drop: | |
| 816 | + netif_tx_stop_all_queues(ndev); | |
| 817 | + ndev->stats.tx_dropped++; | |
| 818 | + dev_kfree_skb_any(skb); | |
| 819 | + | |
| 820 | + return NET_XMIT_DROP; | |
| 821 | +} | |
| 822 | + | |
| 823 | +/** | |
| 824 | + * Clean up transmitted skb's from the Tx VRING | |
| 825 | + * | |
| 826 | + * Safe to call from IRQ | |
| 827 | + */ | |
| 828 | +void wil_tx_complete(struct wil6210_priv *wil, int ringid) | |
| 829 | +{ | |
| 830 | + struct device *dev = wil_to_dev(wil); | |
| 831 | + struct vring *vring = &wil->vring_tx[ringid]; | |
| 832 | + | |
| 833 | + if (!vring->va) { | |
| 834 | + wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); | |
| 835 | + return; | |
| 836 | + } | |
| 837 | + | |
| 838 | + wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid); | |
| 839 | + | |
| 840 | + while (!wil_vring_is_empty(vring)) { | |
| 841 | + volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx; | |
| 842 | + dma_addr_t pa; | |
| 843 | + struct sk_buff *skb; | |
| 844 | + if (!(d->dma.status & TX_DMA_STATUS_DU)) | |
| 845 | + break; | |
| 846 | + | |
| 847 | + wil_dbg_TXRX(wil, | |
| 848 | + "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", | |
| 849 | + vring->swtail, d->dma.length, d->dma.status, | |
| 850 | + d->dma.error); | |
| 851 | + wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4, | |
| 852 | + (const void *)d, sizeof(*d), false); | |
| 853 | + | |
| 854 | + pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | |
| 855 | + skb = vring->ctx[vring->swtail]; | |
| 856 | + if (skb) { | |
| 857 | + dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); | |
| 858 | + dev_kfree_skb_any(skb); | |
| 859 | + vring->ctx[vring->swtail] = NULL; | |
| 860 | + } else { | |
| 861 | + dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE); | |
| 862 | + } | |
| 863 | + d->dma.addr_low = 0; | |
| 864 | + d->dma.addr_high = 0; | |
| 865 | + d->dma.length = 0; | |
| 866 | + d->dma.status = TX_DMA_STATUS_DU; | |
| 867 | + vring->swtail = wil_vring_next_tail(vring); | |
| 868 | + } | |
| 869 | + if (wil_vring_avail_tx(vring) > vring->size/4) | |
| 870 | + netif_tx_wake_all_queues(wil_to_ndev(wil)); | |
| 871 | +} | |
| @@ -0,0 +1,362 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 11 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 13 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 14 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#ifndef WIL6210_TXRX_H | |
| 18 | +#define WIL6210_TXRX_H | |
| 19 | + | |
| 20 | +#define BUF_SW_OWNED (1) | |
| 21 | +#define BUF_HW_OWNED (0) | |
| 22 | + | |
| 23 | +/* size of max. Rx packet */ | |
| 24 | +#define RX_BUF_LEN (2048) | |
| 25 | +#define TX_BUF_LEN (2048) | |
| 26 | +/* how many bytes to reserve for rtap header? */ | |
| 27 | +#define WIL6210_RTAP_SIZE (128) | |
| 28 | + | |
| 29 | +/* Tx/Rx path */ | |
| 30 | +/* | |
| 31 | + * Tx descriptor - MAC part | |
| 32 | + * [dword 0] | |
| 33 | + * bit 0.. 9 : lifetime_expiry_value:10 | |
| 34 | + * bit 10 : interrup_en:1 | |
| 35 | + * bit 11 : status_en:1 | |
| 36 | + * bit 12..13 : txss_override:2 | |
| 37 | + * bit 14 : timestamp_insertion:1 | |
| 38 | + * bit 15 : duration_preserve:1 | |
| 39 | + * bit 16..21 : reserved0:6 | |
| 40 | + * bit 22..26 : mcs_index:5 | |
| 41 | + * bit 27 : mcs_en:1 | |
| 42 | + * bit 28..29 : reserved1:2 | |
| 43 | + * bit 30 : reserved2:1 | |
| 44 | + * bit 31 : sn_preserved:1 | |
| 45 | + * [dword 1] | |
| 46 | + * bit 0.. 3 : pkt_mode:4 | |
| 47 | + * bit 4 : pkt_mode_en:1 | |
| 48 | + * bit 5.. 7 : reserved0:3 | |
| 49 | + * bit 8..13 : reserved1:6 | |
| 50 | + * bit 14 : reserved2:1 | |
| 51 | + * bit 15 : ack_policy_en:1 | |
| 52 | + * bit 16..19 : dst_index:4 | |
| 53 | + * bit 20 : dst_index_en:1 | |
| 54 | + * bit 21..22 : ack_policy:2 | |
| 55 | + * bit 23 : lifetime_en:1 | |
| 56 | + * bit 24..30 : max_retry:7 | |
| 57 | + * bit 31 : max_retry_en:1 | |
| 58 | + * [dword 2] | |
| 59 | + * bit 0.. 7 : num_of_descriptors:8 | |
| 60 | + * bit 8..17 : reserved:10 | |
| 61 | + * bit 18..19 : l2_translation_type:2 | |
| 62 | + * bit 20 : snap_hdr_insertion_en:1 | |
| 63 | + * bit 21 : vlan_removal_en:1 | |
| 64 | + * bit 22..31 : reserved0:10 | |
| 65 | + * [dword 3] | |
| 66 | + * bit 0.. 31: ucode_cmd:32 | |
| 67 | + */ | |
| 68 | +struct vring_tx_mac { | |
| 69 | + u32 d[3]; | |
| 70 | + u32 ucode_cmd; | |
| 71 | +} __packed; | |
| 72 | + | |
| 73 | +/* TX MAC Dword 0 */ | |
| 74 | +#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_POS 0 | |
| 75 | +#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_LEN 10 | |
| 76 | +#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_MSK 0x3FF | |
| 77 | + | |
| 78 | +#define MAC_CFG_DESC_TX_0_INTERRUP_EN_POS 10 | |
| 79 | +#define MAC_CFG_DESC_TX_0_INTERRUP_EN_LEN 1 | |
| 80 | +#define MAC_CFG_DESC_TX_0_INTERRUP_EN_MSK 0x400 | |
| 81 | + | |
| 82 | +#define MAC_CFG_DESC_TX_0_STATUS_EN_POS 11 | |
| 83 | +#define MAC_CFG_DESC_TX_0_STATUS_EN_LEN 1 | |
| 84 | +#define MAC_CFG_DESC_TX_0_STATUS_EN_MSK 0x800 | |
| 85 | + | |
| 86 | +#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_POS 12 | |
| 87 | +#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_LEN 2 | |
| 88 | +#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_MSK 0x3000 | |
| 89 | + | |
| 90 | +#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_POS 14 | |
| 91 | +#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_LEN 1 | |
| 92 | +#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_MSK 0x4000 | |
| 93 | + | |
| 94 | +#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_POS 15 | |
| 95 | +#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_LEN 1 | |
| 96 | +#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_MSK 0x8000 | |
| 97 | + | |
| 98 | +#define MAC_CFG_DESC_TX_0_MCS_INDEX_POS 22 | |
| 99 | +#define MAC_CFG_DESC_TX_0_MCS_INDEX_LEN 5 | |
| 100 | +#define MAC_CFG_DESC_TX_0_MCS_INDEX_MSK 0x7C00000 | |
| 101 | + | |
| 102 | +#define MAC_CFG_DESC_TX_0_MCS_EN_POS 27 | |
| 103 | +#define MAC_CFG_DESC_TX_0_MCS_EN_LEN 1 | |
| 104 | +#define MAC_CFG_DESC_TX_0_MCS_EN_MSK 0x8000000 | |
| 105 | + | |
| 106 | +#define MAC_CFG_DESC_TX_0_SN_PRESERVED_POS 31 | |
| 107 | +#define MAC_CFG_DESC_TX_0_SN_PRESERVED_LEN 1 | |
| 108 | +#define MAC_CFG_DESC_TX_0_SN_PRESERVED_MSK 0x80000000 | |
| 109 | + | |
| 110 | +/* TX MAC Dword 1 */ | |
| 111 | +#define MAC_CFG_DESC_TX_1_PKT_MODE_POS 0 | |
| 112 | +#define MAC_CFG_DESC_TX_1_PKT_MODE_LEN 4 | |
| 113 | +#define MAC_CFG_DESC_TX_1_PKT_MODE_MSK 0xF | |
| 114 | + | |
| 115 | +#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS 4 | |
| 116 | +#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1 | |
| 117 | +#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10 | |
| 118 | + | |
| 119 | +#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15 | |
| 120 | +#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1 | |
| 121 | +#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000 | |
| 122 | + | |
| 123 | +#define MAC_CFG_DESC_TX_1_DST_INDEX_POS 16 | |
| 124 | +#define MAC_CFG_DESC_TX_1_DST_INDEX_LEN 4 | |
| 125 | +#define MAC_CFG_DESC_TX_1_DST_INDEX_MSK 0xF0000 | |
| 126 | + | |
| 127 | +#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS 20 | |
| 128 | +#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_LEN 1 | |
| 129 | +#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_MSK 0x100000 | |
| 130 | + | |
| 131 | +#define MAC_CFG_DESC_TX_1_ACK_POLICY_POS 21 | |
| 132 | +#define MAC_CFG_DESC_TX_1_ACK_POLICY_LEN 2 | |
| 133 | +#define MAC_CFG_DESC_TX_1_ACK_POLICY_MSK 0x600000 | |
| 134 | + | |
| 135 | +#define MAC_CFG_DESC_TX_1_LIFETIME_EN_POS 23 | |
| 136 | +#define MAC_CFG_DESC_TX_1_LIFETIME_EN_LEN 1 | |
| 137 | +#define MAC_CFG_DESC_TX_1_LIFETIME_EN_MSK 0x800000 | |
| 138 | + | |
| 139 | +#define MAC_CFG_DESC_TX_1_MAX_RETRY_POS 24 | |
| 140 | +#define MAC_CFG_DESC_TX_1_MAX_RETRY_LEN 7 | |
| 141 | +#define MAC_CFG_DESC_TX_1_MAX_RETRY_MSK 0x7F000000 | |
| 142 | + | |
| 143 | +#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_POS 31 | |
| 144 | +#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_LEN 1 | |
| 145 | +#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_MSK 0x80000000 | |
| 146 | + | |
| 147 | +/* TX MAC Dword 2 */ | |
| 148 | +#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS 0 | |
| 149 | +#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_LEN 8 | |
| 150 | +#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_MSK 0xFF | |
| 151 | + | |
| 152 | +#define MAC_CFG_DESC_TX_2_RESERVED_POS 8 | |
| 153 | +#define MAC_CFG_DESC_TX_2_RESERVED_LEN 10 | |
| 154 | +#define MAC_CFG_DESC_TX_2_RESERVED_MSK 0x3FF00 | |
| 155 | + | |
| 156 | +#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS 18 | |
| 157 | +#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_LEN 2 | |
| 158 | +#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_MSK 0xC0000 | |
| 159 | + | |
| 160 | +#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS 20 | |
| 161 | +#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_LEN 1 | |
| 162 | +#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_MSK 0x100000 | |
| 163 | + | |
| 164 | +#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_POS 21 | |
| 165 | +#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_LEN 1 | |
| 166 | +#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_MSK 0x200000 | |
| 167 | + | |
| 168 | +/* TX MAC Dword 3 */ | |
| 169 | +#define MAC_CFG_DESC_TX_3_UCODE_CMD_POS 0 | |
| 170 | +#define MAC_CFG_DESC_TX_3_UCODE_CMD_LEN 32 | |
| 171 | +#define MAC_CFG_DESC_TX_3_UCODE_CMD_MSK 0xFFFFFFFF | |
| 172 | + | |
| 173 | +/* TX DMA Dword 0 */ | |
| 174 | +#define DMA_CFG_DESC_TX_0_L4_LENGTH_POS 0 | |
| 175 | +#define DMA_CFG_DESC_TX_0_L4_LENGTH_LEN 8 | |
| 176 | +#define DMA_CFG_DESC_TX_0_L4_LENGTH_MSK 0xFF | |
| 177 | + | |
| 178 | +#define DMA_CFG_DESC_TX_0_CMD_EOP_POS 8 | |
| 179 | +#define DMA_CFG_DESC_TX_0_CMD_EOP_LEN 1 | |
| 180 | +#define DMA_CFG_DESC_TX_0_CMD_EOP_MSK 0x100 | |
| 181 | + | |
| 182 | +#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS 10 | |
| 183 | +#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_LEN 1 | |
| 184 | +#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_MSK 0x400 | |
| 185 | + | |
| 186 | +#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS 11 | |
| 187 | +#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_LEN 2 | |
| 188 | +#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_MSK 0x1800 | |
| 189 | + | |
| 190 | +#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_POS 13 | |
| 191 | +#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_LEN 1 | |
| 192 | +#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_MSK 0x2000 | |
| 193 | + | |
| 194 | +#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_POS 14 | |
| 195 | +#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_LEN 1 | |
| 196 | +#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_MSK 0x4000 | |
| 197 | + | |
| 198 | +#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS 15 | |
| 199 | +#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_LEN 1 | |
| 200 | +#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_MSK 0x8000 | |
| 201 | + | |
| 202 | +#define DMA_CFG_DESC_TX_0_QID_POS 16 | |
| 203 | +#define DMA_CFG_DESC_TX_0_QID_LEN 5 | |
| 204 | +#define DMA_CFG_DESC_TX_0_QID_MSK 0x1F0000 | |
| 205 | + | |
| 206 | +#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS 21 | |
| 207 | +#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_LEN 1 | |
| 208 | +#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_MSK 0x200000 | |
| 209 | + | |
| 210 | +#define DMA_CFG_DESC_TX_0_L4_TYPE_POS 30 | |
| 211 | +#define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2 | |
| 212 | +#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 | |
| 213 | + | |
| 214 | + | |
| 215 | +#define TX_DMA_STATUS_DU BIT(0) | |
| 216 | + | |
| 217 | +struct vring_tx_dma { | |
| 218 | + u32 d0; | |
| 219 | + u32 addr_low; | |
| 220 | + u16 addr_high; | |
| 221 | + u8 ip_length; | |
| 222 | + u8 b11; /* 0..6: mac_length; 7:ip_version */ | |
| 223 | + u8 error; /* 0..2: err; 3..7: reserved; */ | |
| 224 | + u8 status; /* 0: used; 1..7; reserved */ | |
| 225 | + u16 length; | |
| 226 | +} __packed; | |
| 227 | + | |
| 228 | +/* | |
| 229 | + * Rx descriptor - MAC part | |
| 230 | + * [dword 0] | |
| 231 | + * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field | |
| 232 | + * bit 4.. 6 : connection_id:3 :The Source index that was found during | |
| 233 | + * Parsing the TA. This field is used to define the source of the packet | |
| 234 | + * bit 7 : reserved:1 | |
| 235 | + * bit 8.. 9 : mac_id:2 : The MAC virtual Ring number (always zero) | |
| 236 | + * bit 10..11 : frame_type:2 : The FC Control (b3-2) - MPDU Type | |
| 237 | + * (management, data, control and extension) | |
| 238 | + * bit 12..15 : frame_subtype:4 : The FC Control (b7-4) - Frame Subtype | |
| 239 | + * bit 16..27 : seq_number:12 The received Sequence number field | |
| 240 | + * bit 28..31 : extended:4 extended subtype | |
| 241 | + * [dword 1] | |
| 242 | + * bit 0.. 3 : reserved | |
| 243 | + * bit 4.. 5 : key_id:2 | |
| 244 | + * bit 6 : decrypt_bypass:1 | |
| 245 | + * bit 7 : security:1 | |
| 246 | + * bit 8.. 9 : ds_bits:2 | |
| 247 | + * bit 10 : a_msdu_present:1 from qos header | |
| 248 | + * bit 11 : a_msdu_type:1 from qos header | |
| 249 | + * bit 12 : a_mpdu:1 part of AMPDU aggregation | |
| 250 | + * bit 13 : broadcast:1 | |
| 251 | + * bit 14 : mutlicast:1 | |
| 252 | + * bit 15 : reserved:1 | |
| 253 | + * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet | |
| 254 | + * is received from | |
| 255 | + * bit 21..24 : mcs:4 | |
| 256 | + * bit 25..28 : mic_icr:4 | |
| 257 | + * bit 29..31 : reserved:3 | |
| 258 | + * [dword 2] | |
| 259 | + * bit 0.. 2 : time_slot:3 The timeslot that the MPDU is received | |
| 260 | + * bit 3 : fc_protocol_ver:1 The FC Control (b0) - Protocol Version | |
| 261 | + * bit 4 : fc_order:1 The FC Control (b15) -Order | |
| 262 | + * bit 5.. 7 : qos_ack_policy:3 The QoS (b6-5) ack policy Field | |
| 263 | + * bit 8 : esop:1 The QoS (b4) ESOP field | |
| 264 | + * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field | |
| 265 | + * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field | |
| 266 | + * bit 15 : qos_ac_constraint:1 | |
| 267 | + * bit 16..31 : pn_15_0:16 low 2 bytes of PN | |
| 268 | + * [dword 3] | |
| 269 | + * bit 0..31 : pn_47_16:32 high 4 bytes of PN | |
| 270 | + */ | |
| 271 | +struct vring_rx_mac { | |
| 272 | + u32 d0; | |
| 273 | + u32 d1; | |
| 274 | + u16 w4; | |
| 275 | + u16 pn_15_0; | |
| 276 | + u32 pn_47_16; | |
| 277 | +} __packed; | |
| 278 | + | |
| 279 | +/* | |
| 280 | + * Rx descriptor - DMA part | |
| 281 | + * [dword 0] | |
| 282 | + * bit 0.. 7 : l4_length:8 layer 4 length | |
| 283 | + * bit 8.. 9 : reserved:2 | |
| 284 | + * bit 10 : cmd_dma_it:1 | |
| 285 | + * bit 11..15 : reserved:5 | |
| 286 | + * bit 16..29 : phy_info_length:14 | |
| 287 | + * bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field | |
| 288 | + * [dword 1] | |
| 289 | + * bit 0..31 : addr_low:32 The payload buffer low address | |
| 290 | + * [dword 2] | |
| 291 | + * bit 0..15 : addr_high:16 The payload buffer high address | |
| 292 | + * bit 16..23 : ip_length:8 | |
| 293 | + * bit 24..30 : mac_length:7 | |
| 294 | + * bit 31 : ip_version:1 | |
| 295 | + * [dword 3] | |
| 296 | + * [byte 12] error | |
| 297 | + * [byte 13] status | |
| 298 | + * bit 0 : du:1 | |
| 299 | + * bit 1 : eop:1 | |
| 300 | + * bit 2 : error:1 | |
| 301 | + * bit 3 : mi:1 | |
| 302 | + * bit 4 : l3_identified:1 | |
| 303 | + * bit 5 : l4_identified:1 | |
| 304 | + * bit 6 : phy_info_included:1 | |
| 305 | + * bit 7 : reserved:1 | |
| 306 | + * [word 7] length | |
| 307 | + * | |
| 308 | + */ | |
| 309 | + | |
| 310 | +#define RX_DMA_D0_CMD_DMA_IT BIT(10) | |
| 311 | + | |
| 312 | +#define RX_DMA_STATUS_DU BIT(0) | |
| 313 | +#define RX_DMA_STATUS_ERROR BIT(2) | |
| 314 | +#define RX_DMA_STATUS_PHY_INFO BIT(6) | |
| 315 | + | |
| 316 | +struct vring_rx_dma { | |
| 317 | + u32 d0; | |
| 318 | + u32 addr_low; | |
| 319 | + u16 addr_high; | |
| 320 | + u8 ip_length; | |
| 321 | + u8 b11; | |
| 322 | + u8 error; | |
| 323 | + u8 status; | |
| 324 | + u16 length; | |
| 325 | +} __packed; | |
| 326 | + | |
| 327 | +struct vring_tx_desc { | |
| 328 | + struct vring_tx_mac mac; | |
| 329 | + struct vring_tx_dma dma; | |
| 330 | +} __packed; | |
| 331 | + | |
| 332 | +struct vring_rx_desc { | |
| 333 | + struct vring_rx_mac mac; | |
| 334 | + struct vring_rx_dma dma; | |
| 335 | +} __packed; | |
| 336 | + | |
| 337 | +union vring_desc { | |
| 338 | + struct vring_tx_desc tx; | |
| 339 | + struct vring_rx_desc rx; | |
| 340 | +} __packed; | |
| 341 | + | |
| 342 | +static inline int wil_rxdesc_phy_length(volatile struct vring_rx_desc *d) | |
| 343 | +{ | |
| 344 | + return WIL_GET_BITS(d->dma.d0, 16, 29); | |
| 345 | +} | |
| 346 | + | |
| 347 | +static inline int wil_rxdesc_mcs(volatile struct vring_rx_desc *d) | |
| 348 | +{ | |
| 349 | + return WIL_GET_BITS(d->mac.d1, 21, 24); | |
| 350 | +} | |
| 351 | + | |
| 352 | +static inline int wil_rxdesc_ds_bits(volatile struct vring_rx_desc *d) | |
| 353 | +{ | |
| 354 | + return WIL_GET_BITS(d->mac.d1, 8, 9); | |
| 355 | +} | |
| 356 | + | |
| 357 | +static inline int wil_rxdesc_ftype(volatile struct vring_rx_desc *d) | |
| 358 | +{ | |
| 359 | + return WIL_GET_BITS(d->mac.d0, 10, 11); | |
| 360 | +} | |
| 361 | + | |
| 362 | +#endif /* WIL6210_TXRX_H */ | |
| @@ -0,0 +1,363 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 11 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 13 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 14 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#ifndef __WIL6210_H__ | |
| 18 | +#define __WIL6210_H__ | |
| 19 | + | |
| 20 | +#include <linux/netdevice.h> | |
| 21 | +#include <linux/wireless.h> | |
| 22 | +#include <net/cfg80211.h> | |
| 23 | + | |
| 24 | +#include "dbg_hexdump.h" | |
| 25 | + | |
| 26 | +#define WIL_NAME "wil6210" | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * extract bits [@b0:@b1] (inclusive) from the value @x | |
| 30 | + * it should be @b0 <= @b1, or result is incorrect | |
| 31 | + */ | |
| 32 | +static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) | |
| 33 | +{ | |
| 34 | + return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1); | |
| 35 | +} | |
| 36 | + | |
| 37 | +#define WIL6210_MEM_SIZE (2*1024*1024UL) | |
| 38 | + | |
| 39 | +#define WIL6210_TX_QUEUES (4) | |
| 40 | + | |
| 41 | +#define WIL6210_RX_RING_SIZE (128) | |
| 42 | +#define WIL6210_TX_RING_SIZE (128) | |
| 43 | +#define WIL6210_MAX_TX_RINGS (24) | |
| 44 | + | |
| 45 | +/* Hardware definitions begin */ | |
| 46 | + | |
| 47 | +/* | |
| 48 | + * Mapping | |
| 49 | + * RGF File | Host addr | FW addr | |
| 50 | + * | | | |
| 51 | + * user_rgf | 0x000000 | 0x880000 | |
| 52 | + * dma_rgf | 0x001000 | 0x881000 | |
| 53 | + * pcie_rgf | 0x002000 | 0x882000 | |
| 54 | + * | | | |
| 55 | + */ | |
| 56 | + | |
| 57 | +/* Where various structures placed in host address space */ | |
| 58 | +#define WIL6210_FW_HOST_OFF (0x880000UL) | |
| 59 | + | |
| 60 | +#define HOSTADDR(fwaddr) (fwaddr - WIL6210_FW_HOST_OFF) | |
| 61 | + | |
| 62 | +/* | |
| 63 | + * Interrupt control registers block | |
| 64 | + * | |
| 65 | + * each interrupt controlled by the same bit in all registers | |
| 66 | + */ | |
| 67 | +struct RGF_ICR { | |
| 68 | + u32 ICC; /* Cause Control, RW: 0 - W1C, 1 - COR */ | |
| 69 | + u32 ICR; /* Cause, W1C/COR depending on ICC */ | |
| 70 | + u32 ICM; /* Cause masked (ICR & ~IMV), W1C/COR depending on ICC */ | |
| 71 | + u32 ICS; /* Cause Set, WO */ | |
| 72 | + u32 IMV; /* Mask, RW+S/C */ | |
| 73 | + u32 IMS; /* Mask Set, write 1 to set */ | |
| 74 | + u32 IMC; /* Mask Clear, write 1 to clear */ | |
| 75 | +} __packed; | |
| 76 | + | |
| 77 | +/* registers - FW addresses */ | |
| 78 | +#define RGF_USER_USER_SCRATCH_PAD (0x8802bc) | |
| 79 | +#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ | |
| 80 | + #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) | |
| 81 | +#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) | |
| 82 | +#define RGF_USER_MAC_CPU_0 (0x8801fc) | |
| 83 | +#define RGF_USER_USER_CPU_0 (0x8801e0) | |
| 84 | +#define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04) | |
| 85 | +#define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08) | |
| 86 | +#define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c) | |
| 87 | +#define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10) | |
| 88 | + | |
| 89 | +#define RGF_DMA_PSEUDO_CAUSE (0x881c68) | |
| 90 | +#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) | |
| 91 | +#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) | |
| 92 | + #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0) | |
| 93 | + #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) | |
| 94 | + #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) | |
| 95 | + | |
| 96 | +#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ | |
| 97 | + #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) | |
| 98 | + #define BIT_DMA_EP_TX_ICR_TX_DONE_N(n) BIT(n+1) /* n = [0..23] */ | |
| 99 | +#define RGF_DMA_EP_RX_ICR (0x881bd0) /* struct RGF_ICR */ | |
| 100 | + #define BIT_DMA_EP_RX_ICR_RX_DONE BIT(0) | |
| 101 | +#define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */ | |
| 102 | + #define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0) | |
| 103 | + #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) | |
| 104 | + #define BIT_DMA_EP_MISC_ICR_FW_INT0 BIT(28) | |
| 105 | + #define BIT_DMA_EP_MISC_ICR_FW_INT1 BIT(29) | |
| 106 | + | |
| 107 | +/* Interrupt moderation control */ | |
| 108 | +#define RGF_DMA_ITR_CNT_TRSH (0x881c5c) | |
| 109 | +#define RGF_DMA_ITR_CNT_DATA (0x881c60) | |
| 110 | +#define RGF_DMA_ITR_CNT_CRL (0x881C64) | |
| 111 | + #define BIT_DMA_ITR_CNT_CRL_EN BIT(0) | |
| 112 | + #define BIT_DMA_ITR_CNT_CRL_EXT_TICK BIT(1) | |
| 113 | + #define BIT_DMA_ITR_CNT_CRL_FOREVER BIT(2) | |
| 114 | + #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) | |
| 115 | + #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) | |
| 116 | + | |
| 117 | +/* popular locations */ | |
| 118 | +#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) | |
| 119 | +#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ | |
| 120 | + offsetof(struct RGF_ICR, ICS)) | |
| 121 | +#define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2 | |
| 122 | + | |
| 123 | +/* ISR register bits */ | |
| 124 | +#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0 | |
| 125 | +#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1 | |
| 126 | + | |
| 127 | +/* Hardware definitions end */ | |
| 128 | + | |
| 129 | +struct wil6210_mbox_ring { | |
| 130 | + u32 base; | |
| 131 | + u16 entry_size; /* max. size of mbox entry, incl. all headers */ | |
| 132 | + u16 size; | |
| 133 | + u32 tail; | |
| 134 | + u32 head; | |
| 135 | +} __packed; | |
| 136 | + | |
| 137 | +struct wil6210_mbox_ring_desc { | |
| 138 | + __le32 sync; | |
| 139 | + __le32 addr; | |
| 140 | +} __packed; | |
| 141 | + | |
| 142 | +/* at HOST_OFF_WIL6210_MBOX_CTL */ | |
| 143 | +struct wil6210_mbox_ctl { | |
| 144 | + struct wil6210_mbox_ring tx; | |
| 145 | + struct wil6210_mbox_ring rx; | |
| 146 | +} __packed; | |
| 147 | + | |
| 148 | +struct wil6210_mbox_hdr { | |
| 149 | + __le16 seq; | |
| 150 | + __le16 len; /* payload, bytes after this header */ | |
| 151 | + __le16 type; | |
| 152 | + u8 flags; | |
| 153 | + u8 reserved; | |
| 154 | +} __packed; | |
| 155 | + | |
| 156 | +#define WIL_MBOX_HDR_TYPE_WMI (0) | |
| 157 | + | |
| 158 | +/* max. value for wil6210_mbox_hdr.len */ | |
| 159 | +#define MAX_MBOXITEM_SIZE (240) | |
| 160 | + | |
| 161 | +struct wil6210_mbox_hdr_wmi { | |
| 162 | + u8 reserved0[2]; | |
| 163 | + __le16 id; | |
| 164 | + __le16 info1; /* bits [0..3] - device_id, rest - unused */ | |
| 165 | + u8 reserved1[2]; | |
| 166 | +} __packed; | |
| 167 | + | |
| 168 | +struct pending_wmi_event { | |
| 169 | + struct list_head list; | |
| 170 | + struct { | |
| 171 | + struct wil6210_mbox_hdr hdr; | |
| 172 | + struct wil6210_mbox_hdr_wmi wmi; | |
| 173 | + u8 data[0]; | |
| 174 | + } __packed event; | |
| 175 | +}; | |
| 176 | + | |
| 177 | +union vring_desc; | |
| 178 | + | |
| 179 | +struct vring { | |
| 180 | + dma_addr_t pa; | |
| 181 | + volatile union vring_desc *va; /* vring_desc[size], WriteBack by DMA */ | |
| 182 | + u16 size; /* number of vring_desc elements */ | |
| 183 | + u32 swtail; | |
| 184 | + u32 swhead; | |
| 185 | + u32 hwtail; /* write here to inform hw */ | |
| 186 | + void **ctx; /* void *ctx[size] - software context */ | |
| 187 | +}; | |
| 188 | + | |
| 189 | +enum { /* for wil6210_priv.status */ | |
| 190 | + wil_status_fwready = 0, | |
| 191 | + wil_status_fwconnected, | |
| 192 | + wil_status_dontscan, | |
| 193 | + wil_status_irqen, /* FIXME: interrupts enabled - for debug */ | |
| 194 | +}; | |
| 195 | + | |
| 196 | +struct pci_dev; | |
| 197 | + | |
| 198 | +struct wil6210_stats { | |
| 199 | + u64 tsf; | |
| 200 | + u32 snr; | |
| 201 | + u16 last_mcs_rx; | |
| 202 | + u16 bf_mcs; /* last BF, used for Tx */ | |
| 203 | + u16 my_rx_sector; | |
| 204 | + u16 my_tx_sector; | |
| 205 | + u16 peer_rx_sector; | |
| 206 | + u16 peer_tx_sector; | |
| 207 | +}; | |
| 208 | + | |
| 209 | +struct wil6210_priv { | |
| 210 | + struct pci_dev *pdev; | |
| 211 | + int n_msi; | |
| 212 | + struct wireless_dev *wdev; | |
| 213 | + void __iomem *csr; | |
| 214 | + ulong status; | |
| 215 | + /* profile */ | |
| 216 | + u32 monitor_flags; | |
| 217 | + u32 secure_pcp; /* create secure PCP? */ | |
| 218 | + int sinfo_gen; | |
| 219 | + /* cached ISR registers */ | |
| 220 | + u32 isr_misc; | |
| 221 | + /* mailbox related */ | |
| 222 | + struct mutex wmi_mutex; | |
| 223 | + struct wil6210_mbox_ctl mbox_ctl; | |
| 224 | + struct completion wmi_ready; | |
| 225 | + u16 wmi_seq; | |
| 226 | + u16 reply_id; /**< wait for this WMI event */ | |
| 227 | + void *reply_buf; | |
| 228 | + u16 reply_size; | |
| 229 | + struct workqueue_struct *wmi_wq; /* for deferred calls */ | |
| 230 | + struct work_struct wmi_event_worker; | |
| 231 | + struct workqueue_struct *wmi_wq_conn; /* for connect worker */ | |
| 232 | + struct work_struct wmi_connect_worker; | |
| 233 | + struct work_struct disconnect_worker; | |
| 234 | + struct timer_list connect_timer; | |
| 235 | + int pending_connect_cid; | |
| 236 | + struct list_head pending_wmi_ev; | |
| 237 | + /* | |
| 238 | + * protect pending_wmi_ev | |
| 239 | + * - fill in IRQ from wil6210_irq_misc, | |
| 240 | + * - consumed in thread by wmi_event_worker | |
| 241 | + */ | |
| 242 | + spinlock_t wmi_ev_lock; | |
| 243 | + /* DMA related */ | |
| 244 | + struct vring vring_rx; | |
| 245 | + struct vring vring_tx[WIL6210_MAX_TX_RINGS]; | |
| 246 | + u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN]; | |
| 247 | + /* scan */ | |
| 248 | + struct cfg80211_scan_request *scan_request; | |
| 249 | + | |
| 250 | + struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ | |
| 251 | + /* statistics */ | |
| 252 | + struct wil6210_stats stats; | |
| 253 | + /* debugfs */ | |
| 254 | + struct dentry *debug; | |
| 255 | + struct debugfs_blob_wrapper fw_code_blob; | |
| 256 | + struct debugfs_blob_wrapper fw_data_blob; | |
| 257 | + struct debugfs_blob_wrapper fw_peri_blob; | |
| 258 | + struct debugfs_blob_wrapper uc_code_blob; | |
| 259 | + struct debugfs_blob_wrapper uc_data_blob; | |
| 260 | + struct debugfs_blob_wrapper rgf_blob; | |
| 261 | +}; | |
| 262 | + | |
| 263 | +#define wil_to_wiphy(i) (i->wdev->wiphy) | |
| 264 | +#define wil_to_dev(i) (wiphy_dev(wil_to_wiphy(i))) | |
| 265 | +#define wiphy_to_wil(w) (struct wil6210_priv *)(wiphy_priv(w)) | |
| 266 | +#define wil_to_wdev(i) (i->wdev) | |
| 267 | +#define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w)) | |
| 268 | +#define wil_to_ndev(i) (wil_to_wdev(i)->netdev) | |
| 269 | +#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) | |
| 270 | + | |
| 271 | +#define wil_dbg(wil, fmt, arg...) netdev_dbg(wil_to_ndev(wil), fmt, ##arg) | |
| 272 | +#define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg) | |
| 273 | +#define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg) | |
| 274 | + | |
| 275 | +#define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) | |
| 276 | +#define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) | |
| 277 | +#define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) | |
| 278 | + | |
| 279 | +#define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize, \ | |
| 280 | + groupsize, buf, len, ascii) \ | |
| 281 | + wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\ | |
| 282 | + prefix_type, rowsize, \ | |
| 283 | + groupsize, buf, len, ascii) | |
| 284 | + | |
| 285 | +#define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize, \ | |
| 286 | + groupsize, buf, len, ascii) \ | |
| 287 | + wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\ | |
| 288 | + prefix_type, rowsize, \ | |
| 289 | + groupsize, buf, len, ascii) | |
| 290 | + | |
| 291 | +void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, | |
| 292 | + size_t count); | |
| 293 | +void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, | |
| 294 | + size_t count); | |
| 295 | + | |
| 296 | +void *wil_if_alloc(struct device *dev, void __iomem *csr); | |
| 297 | +void wil_if_free(struct wil6210_priv *wil); | |
| 298 | +int wil_if_add(struct wil6210_priv *wil); | |
| 299 | +void wil_if_remove(struct wil6210_priv *wil); | |
| 300 | +int wil_priv_init(struct wil6210_priv *wil); | |
| 301 | +void wil_priv_deinit(struct wil6210_priv *wil); | |
| 302 | +int wil_reset(struct wil6210_priv *wil); | |
| 303 | +void wil_link_on(struct wil6210_priv *wil); | |
| 304 | +void wil_link_off(struct wil6210_priv *wil); | |
| 305 | +int wil_up(struct wil6210_priv *wil); | |
| 306 | +int wil_down(struct wil6210_priv *wil); | |
| 307 | +void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); | |
| 308 | + | |
| 309 | +void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); | |
| 310 | +void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); | |
| 311 | +int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, | |
| 312 | + struct wil6210_mbox_hdr *hdr); | |
| 313 | +int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len); | |
| 314 | +void wmi_recv_cmd(struct wil6210_priv *wil); | |
| 315 | +int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, | |
| 316 | + u16 reply_id, void *reply, u8 reply_size, int to_msec); | |
| 317 | +void wmi_connect_worker(struct work_struct *work); | |
| 318 | +void wmi_event_worker(struct work_struct *work); | |
| 319 | +void wmi_event_flush(struct wil6210_priv *wil); | |
| 320 | +int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid); | |
| 321 | +int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid); | |
| 322 | +int wmi_set_channel(struct wil6210_priv *wil, int channel); | |
| 323 | +int wmi_get_channel(struct wil6210_priv *wil, int *channel); | |
| 324 | +int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb); | |
| 325 | +int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index, | |
| 326 | + const void *mac_addr); | |
| 327 | +int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, | |
| 328 | + const void *mac_addr, int key_len, const void *key); | |
| 329 | +int wmi_echo(struct wil6210_priv *wil); | |
| 330 | +int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); | |
| 331 | + | |
| 332 | +int wil6210_init_irq(struct wil6210_priv *wil, int irq); | |
| 333 | +void wil6210_fini_irq(struct wil6210_priv *wil, int irq); | |
| 334 | +void wil6210_disable_irq(struct wil6210_priv *wil); | |
| 335 | +void wil6210_enable_irq(struct wil6210_priv *wil); | |
| 336 | + | |
| 337 | +int wil6210_debugfs_init(struct wil6210_priv *wil); | |
| 338 | +void wil6210_debugfs_remove(struct wil6210_priv *wil); | |
| 339 | + | |
| 340 | +struct wireless_dev *wil_cfg80211_init(struct device *dev); | |
| 341 | +void wil_wdev_free(struct wil6210_priv *wil); | |
| 342 | + | |
| 343 | +int wmi_set_mac_address(struct wil6210_priv *wil, void *addr); | |
| 344 | +int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype); | |
| 345 | +void wil6210_disconnect(struct wil6210_priv *wil, void *bssid); | |
| 346 | + | |
| 347 | +int wil_rx_init(struct wil6210_priv *wil); | |
| 348 | +void wil_rx_fini(struct wil6210_priv *wil); | |
| 349 | + | |
| 350 | +/* TX API */ | |
| 351 | +int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | |
| 352 | + int cid, int tid); | |
| 353 | +void wil_vring_fini_tx(struct wil6210_priv *wil, int id); | |
| 354 | + | |
| 355 | +netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); | |
| 356 | +void wil_tx_complete(struct wil6210_priv *wil, int ringid); | |
| 357 | + | |
| 358 | +/* RX API */ | |
| 359 | +void wil_rx_handle(struct wil6210_priv *wil); | |
| 360 | + | |
| 361 | +int wil_iftype_nl2wmi(enum nl80211_iftype type); | |
| 362 | + | |
| 363 | +#endif /* __WIL6210_H__ */ | |
| @@ -0,0 +1,975 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 11 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 13 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 14 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/pci.h> | |
| 18 | +#include <linux/io.h> | |
| 19 | +#include <linux/list.h> | |
| 20 | +#include <linux/etherdevice.h> | |
| 21 | + | |
| 22 | +#include "wil6210.h" | |
| 23 | +#include "wmi.h" | |
| 24 | + | |
| 25 | +/** | |
| 26 | + * WMI event receiving - theory of operations | |
| 27 | + * | |
| 28 | + * When firmware about to report WMI event, it fills memory area | |
| 29 | + * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for | |
| 30 | + * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler. | |
| 31 | + * | |
| 32 | + * @wmi_recv_cmd reads event, allocates memory chunk and attaches it to the | |
| 33 | + * event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up | |
| 34 | + * and handles events within the @wmi_event_worker. Every event get detached | |
| 35 | + * from list, processed and deleted. | |
| 36 | + * | |
| 37 | + * Purpose for this mechanism is to release IRQ thread; otherwise, | |
| 38 | + * if WMI event handling involves another WMI command flow, this 2-nd flow | |
| 39 | + * won't be completed because of blocked IRQ thread. | |
| 40 | + */ | |
| 41 | + | |
| 42 | +/** | |
| 43 | + * Addressing - theory of operations | |
| 44 | + * | |
| 45 | + * There are several buses present on the WIL6210 card. | |
| 46 | + * Same memory areas are visible at different address on | |
| 47 | + * the different busses. There are 3 main bus masters: | |
| 48 | + * - MAC CPU (ucode) | |
| 49 | + * - User CPU (firmware) | |
| 50 | + * - AHB (host) | |
| 51 | + * | |
| 52 | + * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing | |
| 53 | + * AHB addresses starting from 0x880000 | |
| 54 | + * | |
| 55 | + * Internally, firmware uses addresses that allows faster access but | |
| 56 | + * are invisible from the host. To read from these addresses, alternative | |
| 57 | + * AHB address must be used. | |
| 58 | + * | |
| 59 | + * Memory mapping | |
| 60 | + * Linker address PCI/Host address | |
| 61 | + * 0x880000 .. 0xa80000 2Mb BAR0 | |
| 62 | + * 0x800000 .. 0x807000 0x900000 .. 0x907000 28k DCCM | |
| 63 | + * 0x840000 .. 0x857000 0x908000 .. 0x91f000 92k PERIPH | |
| 64 | + */ | |
| 65 | + | |
| 66 | +/** | |
| 67 | + * @fw_mapping provides memory remapping table | |
| 68 | + */ | |
| 69 | +static const struct { | |
| 70 | + u32 from; /* linker address - from, inclusive */ | |
| 71 | + u32 to; /* linker address - to, exclusive */ | |
| 72 | + u32 host; /* PCI/Host address - BAR0 + 0x880000 */ | |
| 73 | +} fw_mapping[] = { | |
| 74 | + {0x000000, 0x040000, 0x8c0000}, /* FW code RAM 256k */ | |
| 75 | + {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */ | |
| 76 | + {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */ | |
| 77 | + {0x880000, 0x88a000, 0x880000}, /* various RGF */ | |
| 78 | + {0x8c0000, 0x932000, 0x8c0000}, /* trivial mapping for upper area */ | |
| 79 | + /* | |
| 80 | + * 920000..930000 ucode code RAM | |
| 81 | + * 930000..932000 ucode data RAM | |
| 82 | + */ | |
| 83 | +}; | |
| 84 | + | |
| 85 | +/** | |
| 86 | + * return AHB address for given firmware/ucode internal (linker) address | |
| 87 | + * @x - internal address | |
| 88 | + * If address have no valid AHB mapping, return 0 | |
| 89 | + */ | |
| 90 | +static u32 wmi_addr_remap(u32 x) | |
| 91 | +{ | |
| 92 | + uint i; | |
| 93 | + | |
| 94 | + for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { | |
| 95 | + if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to)) | |
| 96 | + return x + fw_mapping[i].host - fw_mapping[i].from; | |
| 97 | + } | |
| 98 | + | |
| 99 | + return 0; | |
| 100 | +} | |
| 101 | + | |
| 102 | +/** | |
| 103 | + * Check address validity for WMI buffer; remap if needed | |
| 104 | + * @ptr - internal (linker) fw/ucode address | |
| 105 | + * | |
| 106 | + * Valid buffer should be DWORD aligned | |
| 107 | + * | |
| 108 | + * return address for accessing buffer from the host; | |
| 109 | + * if buffer is not valid, return NULL. | |
| 110 | + */ | |
| 111 | +void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) | |
| 112 | +{ | |
| 113 | + u32 off; | |
| 114 | + u32 ptr = le32_to_cpu(ptr_); | |
| 115 | + | |
| 116 | + if (ptr % 4) | |
| 117 | + return NULL; | |
| 118 | + | |
| 119 | + ptr = wmi_addr_remap(ptr); | |
| 120 | + if (ptr < WIL6210_FW_HOST_OFF) | |
| 121 | + return NULL; | |
| 122 | + | |
| 123 | + off = HOSTADDR(ptr); | |
| 124 | + if (off > WIL6210_MEM_SIZE - 4) | |
| 125 | + return NULL; | |
| 126 | + | |
| 127 | + return wil->csr + off; | |
| 128 | +} | |
| 129 | + | |
| 130 | +/** | |
| 131 | + * Check address validity | |
| 132 | + */ | |
| 133 | +void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr) | |
| 134 | +{ | |
| 135 | + u32 off; | |
| 136 | + | |
| 137 | + if (ptr % 4) | |
| 138 | + return NULL; | |
| 139 | + | |
| 140 | + if (ptr < WIL6210_FW_HOST_OFF) | |
| 141 | + return NULL; | |
| 142 | + | |
| 143 | + off = HOSTADDR(ptr); | |
| 144 | + if (off > WIL6210_MEM_SIZE - 4) | |
| 145 | + return NULL; | |
| 146 | + | |
| 147 | + return wil->csr + off; | |
| 148 | +} | |
| 149 | + | |
| 150 | +int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, | |
| 151 | + struct wil6210_mbox_hdr *hdr) | |
| 152 | +{ | |
| 153 | + void __iomem *src = wmi_buffer(wil, ptr); | |
| 154 | + if (!src) | |
| 155 | + return -EINVAL; | |
| 156 | + | |
| 157 | + wil_memcpy_fromio_32(hdr, src, sizeof(*hdr)); | |
| 158 | + | |
| 159 | + return 0; | |
| 160 | +} | |
| 161 | + | |
| 162 | +static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | |
| 163 | +{ | |
| 164 | + struct { | |
| 165 | + struct wil6210_mbox_hdr hdr; | |
| 166 | + struct wil6210_mbox_hdr_wmi wmi; | |
| 167 | + } __packed cmd = { | |
| 168 | + .hdr = { | |
| 169 | + .type = WIL_MBOX_HDR_TYPE_WMI, | |
| 170 | + .flags = 0, | |
| 171 | + .len = cpu_to_le16(sizeof(cmd.wmi) + len), | |
| 172 | + }, | |
| 173 | + .wmi = { | |
| 174 | + .id = cpu_to_le16(cmdid), | |
| 175 | + .info1 = 0, | |
| 176 | + }, | |
| 177 | + }; | |
| 178 | + struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx; | |
| 179 | + struct wil6210_mbox_ring_desc d_head; | |
| 180 | + u32 next_head; | |
| 181 | + void __iomem *dst; | |
| 182 | + void __iomem *head = wmi_addr(wil, r->head); | |
| 183 | + uint retry; | |
| 184 | + | |
| 185 | + if (sizeof(cmd) + len > r->entry_size) { | |
| 186 | + wil_err(wil, "WMI size too large: %d bytes, max is %d\n", | |
| 187 | + (int)(sizeof(cmd) + len), r->entry_size); | |
| 188 | + return -ERANGE; | |
| 189 | + | |
| 190 | + } | |
| 191 | + | |
| 192 | + might_sleep(); | |
| 193 | + | |
| 194 | + if (!test_bit(wil_status_fwready, &wil->status)) { | |
| 195 | + wil_err(wil, "FW not ready\n"); | |
| 196 | + return -EAGAIN; | |
| 197 | + } | |
| 198 | + | |
| 199 | + if (!head) { | |
| 200 | + wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head); | |
| 201 | + return -EINVAL; | |
| 202 | + } | |
| 203 | + /* read Tx head till it is not busy */ | |
| 204 | + for (retry = 5; retry > 0; retry--) { | |
| 205 | + wil_memcpy_fromio_32(&d_head, head, sizeof(d_head)); | |
| 206 | + if (d_head.sync == 0) | |
| 207 | + break; | |
| 208 | + msleep(20); | |
| 209 | + } | |
| 210 | + if (d_head.sync != 0) { | |
| 211 | + wil_err(wil, "WMI head busy\n"); | |
| 212 | + return -EBUSY; | |
| 213 | + } | |
| 214 | + /* next head */ | |
| 215 | + next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size); | |
| 216 | + wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); | |
| 217 | + /* wait till FW finish with previous command */ | |
| 218 | + for (retry = 5; retry > 0; retry--) { | |
| 219 | + r->tail = ioread32(wil->csr + HOST_MBOX + | |
| 220 | + offsetof(struct wil6210_mbox_ctl, tx.tail)); | |
| 221 | + if (next_head != r->tail) | |
| 222 | + break; | |
| 223 | + msleep(20); | |
| 224 | + } | |
| 225 | + if (next_head == r->tail) { | |
| 226 | + wil_err(wil, "WMI ring full\n"); | |
| 227 | + return -EBUSY; | |
| 228 | + } | |
| 229 | + dst = wmi_buffer(wil, d_head.addr); | |
| 230 | + if (!dst) { | |
| 231 | + wil_err(wil, "invalid WMI buffer: 0x%08x\n", | |
| 232 | + le32_to_cpu(d_head.addr)); | |
| 233 | + return -EINVAL; | |
| 234 | + } | |
| 235 | + cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq); | |
| 236 | + /* set command */ | |
| 237 | + wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len); | |
| 238 | + wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, | |
| 239 | + sizeof(cmd), true); | |
| 240 | + wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, | |
| 241 | + len, true); | |
| 242 | + wil_memcpy_toio_32(dst, &cmd, sizeof(cmd)); | |
| 243 | + wil_memcpy_toio_32(dst + sizeof(cmd), buf, len); | |
| 244 | + /* mark entry as full */ | |
| 245 | + iowrite32(1, wil->csr + HOSTADDR(r->head) + | |
| 246 | + offsetof(struct wil6210_mbox_ring_desc, sync)); | |
| 247 | + /* advance next ptr */ | |
| 248 | + iowrite32(r->head = next_head, wil->csr + HOST_MBOX + | |
| 249 | + offsetof(struct wil6210_mbox_ctl, tx.head)); | |
| 250 | + | |
| 251 | + /* interrupt to FW */ | |
| 252 | + iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT); | |
| 253 | + | |
| 254 | + return 0; | |
| 255 | +} | |
| 256 | + | |
| 257 | +int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | |
| 258 | +{ | |
| 259 | + int rc; | |
| 260 | + | |
| 261 | + mutex_lock(&wil->wmi_mutex); | |
| 262 | + rc = __wmi_send(wil, cmdid, buf, len); | |
| 263 | + mutex_unlock(&wil->wmi_mutex); | |
| 264 | + | |
| 265 | + return rc; | |
| 266 | +} | |
| 267 | + | |
| 268 | +/*=== Event handlers ===*/ | |
| 269 | +static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) | |
| 270 | +{ | |
| 271 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 272 | + struct wireless_dev *wdev = wil->wdev; | |
| 273 | + struct wmi_ready_event *evt = d; | |
| 274 | + u32 ver = le32_to_cpu(evt->sw_version); | |
| 275 | + | |
| 276 | + wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac); | |
| 277 | + | |
| 278 | + if (!is_valid_ether_addr(ndev->dev_addr)) { | |
| 279 | + memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); | |
| 280 | + memcpy(ndev->perm_addr, evt->mac, ETH_ALEN); | |
| 281 | + } | |
| 282 | + snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version), | |
| 283 | + "%d", ver); | |
| 284 | +} | |
| 285 | + | |
| 286 | +static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, | |
| 287 | + int len) | |
| 288 | +{ | |
| 289 | + wil_dbg_WMI(wil, "WMI: FW ready\n"); | |
| 290 | + | |
| 291 | + set_bit(wil_status_fwready, &wil->status); | |
| 292 | + /* reuse wmi_ready for the firmware ready indication */ | |
| 293 | + complete(&wil->wmi_ready); | |
| 294 | +} | |
| 295 | + | |
| 296 | +static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | |
| 297 | +{ | |
| 298 | + struct wmi_rx_mgmt_packet_event *data = d; | |
| 299 | + struct wiphy *wiphy = wil_to_wiphy(wil); | |
| 300 | + struct ieee80211_mgmt *rx_mgmt_frame = | |
| 301 | + (struct ieee80211_mgmt *)data->payload; | |
| 302 | + int ch_no = data->info.channel+1; | |
| 303 | + u32 freq = ieee80211_channel_to_frequency(ch_no, | |
| 304 | + IEEE80211_BAND_60GHZ); | |
| 305 | + struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); | |
| 306 | + /* TODO convert LE to CPU */ | |
| 307 | + s32 signal = 0; /* TODO */ | |
| 308 | + __le16 fc = rx_mgmt_frame->frame_control; | |
| 309 | + u32 d_len = le32_to_cpu(data->info.len); | |
| 310 | + u16 d_status = le16_to_cpu(data->info.status); | |
| 311 | + | |
| 312 | + wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n", | |
| 313 | + data->info.channel, data->info.mcs, data->info.snr); | |
| 314 | + wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len, | |
| 315 | + le16_to_cpu(data->info.stype)); | |
| 316 | + wil_dbg_WMI(wil, "qid %d mid %d cid %d\n", | |
| 317 | + data->info.qid, data->info.mid, data->info.cid); | |
| 318 | + | |
| 319 | + if (!channel) { | |
| 320 | + wil_err(wil, "Frame on unsupported channel\n"); | |
| 321 | + return; | |
| 322 | + } | |
| 323 | + | |
| 324 | + if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) { | |
| 325 | + struct cfg80211_bss *bss; | |
| 326 | + u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp); | |
| 327 | + u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info); | |
| 328 | + u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int); | |
| 329 | + const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; | |
| 330 | + size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, | |
| 331 | + u.beacon.variable); | |
| 332 | + wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap); | |
| 333 | + | |
| 334 | + bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid, | |
| 335 | + tsf, cap, bi, ie_buf, ie_len, | |
| 336 | + signal, GFP_KERNEL); | |
| 337 | + if (bss) { | |
| 338 | + wil_dbg_WMI(wil, "Added BSS %pM\n", | |
| 339 | + rx_mgmt_frame->bssid); | |
| 340 | + cfg80211_put_bss(bss); | |
| 341 | + } else { | |
| 342 | + wil_err(wil, "cfg80211_inform_bss() failed\n"); | |
| 343 | + } | |
| 344 | + } | |
| 345 | +} | |
| 346 | + | |
| 347 | +static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, | |
| 348 | + void *d, int len) | |
| 349 | +{ | |
| 350 | + if (wil->scan_request) { | |
| 351 | + struct wmi_scan_complete_event *data = d; | |
| 352 | + bool aborted = (data->status != 0); | |
| 353 | + | |
| 354 | + wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); | |
| 355 | + cfg80211_scan_done(wil->scan_request, aborted); | |
| 356 | + wil->scan_request = NULL; | |
| 357 | + } else { | |
| 358 | + wil_err(wil, "SCAN_COMPLETE while not scanning\n"); | |
| 359 | + } | |
| 360 | +} | |
| 361 | + | |
| 362 | +static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) | |
| 363 | +{ | |
| 364 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 365 | + struct wireless_dev *wdev = wil->wdev; | |
| 366 | + struct wmi_connect_event *evt = d; | |
| 367 | + int ch; /* channel number */ | |
| 368 | + struct station_info sinfo; | |
| 369 | + u8 *assoc_req_ie, *assoc_resp_ie; | |
| 370 | + size_t assoc_req_ielen, assoc_resp_ielen; | |
| 371 | + /* capinfo(u16) + listen_interval(u16) + IEs */ | |
| 372 | + const size_t assoc_req_ie_offset = sizeof(u16) * 2; | |
| 373 | + /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */ | |
| 374 | + const size_t assoc_resp_ie_offset = sizeof(u16) * 3; | |
| 375 | + | |
| 376 | + if (len < sizeof(*evt)) { | |
| 377 | + wil_err(wil, "Connect event too short : %d bytes\n", len); | |
| 378 | + return; | |
| 379 | + } | |
| 380 | + if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len + | |
| 381 | + evt->assoc_resp_len) { | |
| 382 | + wil_err(wil, | |
| 383 | + "Connect event corrupted : %d != %d + %d + %d + %d\n", | |
| 384 | + len, (int)sizeof(*evt), evt->beacon_ie_len, | |
| 385 | + evt->assoc_req_len, evt->assoc_resp_len); | |
| 386 | + return; | |
| 387 | + } | |
| 388 | + ch = evt->channel + 1; | |
| 389 | + wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n", | |
| 390 | + evt->bssid, ch, evt->cid); | |
| 391 | + wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1, | |
| 392 | + evt->assoc_info, len - sizeof(*evt), true); | |
| 393 | + | |
| 394 | + /* figure out IE's */ | |
| 395 | + assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len + | |
| 396 | + assoc_req_ie_offset]; | |
| 397 | + assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset; | |
| 398 | + if (evt->assoc_req_len <= assoc_req_ie_offset) { | |
| 399 | + assoc_req_ie = NULL; | |
| 400 | + assoc_req_ielen = 0; | |
| 401 | + } | |
| 402 | + | |
| 403 | + assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len + | |
| 404 | + evt->assoc_req_len + | |
| 405 | + assoc_resp_ie_offset]; | |
| 406 | + assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset; | |
| 407 | + if (evt->assoc_resp_len <= assoc_resp_ie_offset) { | |
| 408 | + assoc_resp_ie = NULL; | |
| 409 | + assoc_resp_ielen = 0; | |
| 410 | + } | |
| 411 | + | |
| 412 | + if ((wdev->iftype == NL80211_IFTYPE_STATION) || | |
| 413 | + (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { | |
| 414 | + if (wdev->sme_state != CFG80211_SME_CONNECTING) { | |
| 415 | + wil_err(wil, "Not in connecting state\n"); | |
| 416 | + return; | |
| 417 | + } | |
| 418 | + del_timer_sync(&wil->connect_timer); | |
| 419 | + cfg80211_connect_result(ndev, evt->bssid, | |
| 420 | + assoc_req_ie, assoc_req_ielen, | |
| 421 | + assoc_resp_ie, assoc_resp_ielen, | |
| 422 | + WLAN_STATUS_SUCCESS, GFP_KERNEL); | |
| 423 | + | |
| 424 | + } else if ((wdev->iftype == NL80211_IFTYPE_AP) || | |
| 425 | + (wdev->iftype == NL80211_IFTYPE_P2P_GO)) { | |
| 426 | + memset(&sinfo, 0, sizeof(sinfo)); | |
| 427 | + | |
| 428 | + sinfo.generation = wil->sinfo_gen++; | |
| 429 | + | |
| 430 | + if (assoc_req_ie) { | |
| 431 | + sinfo.assoc_req_ies = assoc_req_ie; | |
| 432 | + sinfo.assoc_req_ies_len = assoc_req_ielen; | |
| 433 | + sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; | |
| 434 | + } | |
| 435 | + | |
| 436 | + cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); | |
| 437 | + } | |
| 438 | + set_bit(wil_status_fwconnected, &wil->status); | |
| 439 | + | |
| 440 | + /* FIXME FW can transmit only ucast frames to peer */ | |
| 441 | + /* FIXME real ring_id instead of hard coded 0 */ | |
| 442 | + memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); | |
| 443 | + | |
| 444 | + wil->pending_connect_cid = evt->cid; | |
| 445 | + queue_work(wil->wmi_wq_conn, &wil->wmi_connect_worker); | |
| 446 | +} | |
| 447 | + | |
| 448 | +static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, | |
| 449 | + void *d, int len) | |
| 450 | +{ | |
| 451 | + struct wmi_disconnect_event *evt = d; | |
| 452 | + | |
| 453 | + wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n", | |
| 454 | + evt->bssid, | |
| 455 | + evt->protocol_reason_status, evt->disconnect_reason); | |
| 456 | + | |
| 457 | + wil->sinfo_gen++; | |
| 458 | + | |
| 459 | + wil6210_disconnect(wil, evt->bssid); | |
| 460 | + clear_bit(wil_status_dontscan, &wil->status); | |
| 461 | +} | |
| 462 | + | |
| 463 | +static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) | |
| 464 | +{ | |
| 465 | + struct wmi_notify_req_done_event *evt = d; | |
| 466 | + | |
| 467 | + if (len < sizeof(*evt)) { | |
| 468 | + wil_err(wil, "Short NOTIFY event\n"); | |
| 469 | + return; | |
| 470 | + } | |
| 471 | + | |
| 472 | + wil->stats.tsf = le64_to_cpu(evt->tsf); | |
| 473 | + wil->stats.snr = le32_to_cpu(evt->snr_val); | |
| 474 | + wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs); | |
| 475 | + wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector); | |
| 476 | + wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector); | |
| 477 | + wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); | |
| 478 | + wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); | |
| 479 | + wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n" | |
| 480 | + "BF status 0x%08x SNR 0x%08x\n" | |
| 481 | + "Tx Tpt %d goodput %d Rx goodput %d\n" | |
| 482 | + "Sectors(rx:tx) my %d:%d peer %d:%d\n", | |
| 483 | + wil->stats.bf_mcs, wil->stats.tsf, evt->status, | |
| 484 | + wil->stats.snr, le32_to_cpu(evt->tx_tpt), | |
| 485 | + le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput), | |
| 486 | + wil->stats.my_rx_sector, wil->stats.my_tx_sector, | |
| 487 | + wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); | |
| 488 | +} | |
| 489 | + | |
| 490 | +/* | |
| 491 | + * Firmware reports EAPOL frame using WME event. | |
| 492 | + * Reconstruct Ethernet frame and deliver it via normal Rx | |
| 493 | + */ | |
| 494 | +static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, | |
| 495 | + void *d, int len) | |
| 496 | +{ | |
| 497 | + struct net_device *ndev = wil_to_ndev(wil); | |
| 498 | + struct wmi_eapol_rx_event *evt = d; | |
| 499 | + u16 eapol_len = le16_to_cpu(evt->eapol_len); | |
| 500 | + int sz = eapol_len + ETH_HLEN; | |
| 501 | + struct sk_buff *skb; | |
| 502 | + struct ethhdr *eth; | |
| 503 | + | |
| 504 | + wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len, | |
| 505 | + evt->src_mac); | |
| 506 | + | |
| 507 | + if (eapol_len > 196) { /* TODO: revisit size limit */ | |
| 508 | + wil_err(wil, "EAPOL too large\n"); | |
| 509 | + return; | |
| 510 | + } | |
| 511 | + | |
| 512 | + skb = alloc_skb(sz, GFP_KERNEL); | |
| 513 | + if (!skb) { | |
| 514 | + wil_err(wil, "Failed to allocate skb\n"); | |
| 515 | + return; | |
| 516 | + } | |
| 517 | + eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); | |
| 518 | + memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN); | |
| 519 | + memcpy(eth->h_source, evt->src_mac, ETH_ALEN); | |
| 520 | + eth->h_proto = cpu_to_be16(ETH_P_PAE); | |
| 521 | + memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len); | |
| 522 | + skb->protocol = eth_type_trans(skb, ndev); | |
| 523 | + if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { | |
| 524 | + ndev->stats.rx_packets++; | |
| 525 | + ndev->stats.rx_bytes += skb->len; | |
| 526 | + } else { | |
| 527 | + ndev->stats.rx_dropped++; | |
| 528 | + } | |
| 529 | +} | |
| 530 | + | |
| 531 | +static const struct { | |
| 532 | + int eventid; | |
| 533 | + void (*handler)(struct wil6210_priv *wil, int eventid, | |
| 534 | + void *data, int data_len); | |
| 535 | +} wmi_evt_handlers[] = { | |
| 536 | + {WMI_READY_EVENTID, wmi_evt_ready}, | |
| 537 | + {WMI_FW_READY_EVENTID, wmi_evt_fw_ready}, | |
| 538 | + {WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt}, | |
| 539 | + {WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete}, | |
| 540 | + {WMI_CONNECT_EVENTID, wmi_evt_connect}, | |
| 541 | + {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect}, | |
| 542 | + {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify}, | |
| 543 | + {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx}, | |
| 544 | +}; | |
| 545 | + | |
| 546 | +/* | |
| 547 | + * Run in IRQ context | |
| 548 | + * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev | |
| 549 | + * that will be eventually handled by the @wmi_event_worker in the thread | |
| 550 | + * context of thread "wil6210_wmi" | |
| 551 | + */ | |
| 552 | +void wmi_recv_cmd(struct wil6210_priv *wil) | |
| 553 | +{ | |
| 554 | + struct wil6210_mbox_ring_desc d_tail; | |
| 555 | + struct wil6210_mbox_hdr hdr; | |
| 556 | + struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx; | |
| 557 | + struct pending_wmi_event *evt; | |
| 558 | + u8 *cmd; | |
| 559 | + void __iomem *src; | |
| 560 | + ulong flags; | |
| 561 | + | |
| 562 | + for (;;) { | |
| 563 | + u16 len; | |
| 564 | + | |
| 565 | + r->head = ioread32(wil->csr + HOST_MBOX + | |
| 566 | + offsetof(struct wil6210_mbox_ctl, rx.head)); | |
| 567 | + if (r->tail == r->head) | |
| 568 | + return; | |
| 569 | + | |
| 570 | + /* read cmd from tail */ | |
| 571 | + wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail), | |
| 572 | + sizeof(struct wil6210_mbox_ring_desc)); | |
| 573 | + if (d_tail.sync == 0) { | |
| 574 | + wil_err(wil, "Mbox evt not owned by FW?\n"); | |
| 575 | + return; | |
| 576 | + } | |
| 577 | + | |
| 578 | + if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) { | |
| 579 | + wil_err(wil, "Mbox evt at 0x%08x?\n", | |
| 580 | + le32_to_cpu(d_tail.addr)); | |
| 581 | + return; | |
| 582 | + } | |
| 583 | + | |
| 584 | + len = le16_to_cpu(hdr.len); | |
| 585 | + src = wmi_buffer(wil, d_tail.addr) + | |
| 586 | + sizeof(struct wil6210_mbox_hdr); | |
| 587 | + evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event, | |
| 588 | + event.wmi) + len, 4), | |
| 589 | + GFP_KERNEL); | |
| 590 | + if (!evt) { | |
| 591 | + wil_err(wil, "kmalloc for WMI event (%d) failed\n", | |
| 592 | + len); | |
| 593 | + return; | |
| 594 | + } | |
| 595 | + evt->event.hdr = hdr; | |
| 596 | + cmd = (void *)&evt->event.wmi; | |
| 597 | + wil_memcpy_fromio_32(cmd, src, len); | |
| 598 | + /* mark entry as empty */ | |
| 599 | + iowrite32(0, wil->csr + HOSTADDR(r->tail) + | |
| 600 | + offsetof(struct wil6210_mbox_ring_desc, sync)); | |
| 601 | + /* indicate */ | |
| 602 | + wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n", | |
| 603 | + le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), | |
| 604 | + hdr.flags); | |
| 605 | + if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && | |
| 606 | + (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { | |
| 607 | + wil_dbg_WMI(wil, "WMI event 0x%04x\n", | |
| 608 | + evt->event.wmi.id); | |
| 609 | + } | |
| 610 | + wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1, | |
| 611 | + &evt->event.hdr, sizeof(hdr) + len, true); | |
| 612 | + | |
| 613 | + /* advance tail */ | |
| 614 | + r->tail = r->base + ((r->tail - r->base + | |
| 615 | + sizeof(struct wil6210_mbox_ring_desc)) % r->size); | |
| 616 | + iowrite32(r->tail, wil->csr + HOST_MBOX + | |
| 617 | + offsetof(struct wil6210_mbox_ctl, rx.tail)); | |
| 618 | + | |
| 619 | + /* add to the pending list */ | |
| 620 | + spin_lock_irqsave(&wil->wmi_ev_lock, flags); | |
| 621 | + list_add_tail(&evt->list, &wil->pending_wmi_ev); | |
| 622 | + spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); | |
| 623 | + { | |
| 624 | + int q = queue_work(wil->wmi_wq, | |
| 625 | + &wil->wmi_event_worker); | |
| 626 | + wil_dbg_WMI(wil, "queue_work -> %d\n", q); | |
| 627 | + } | |
| 628 | + } | |
| 629 | +} | |
| 630 | + | |
| 631 | +int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, | |
| 632 | + u16 reply_id, void *reply, u8 reply_size, int to_msec) | |
| 633 | +{ | |
| 634 | + int rc; | |
| 635 | + int remain; | |
| 636 | + | |
| 637 | + mutex_lock(&wil->wmi_mutex); | |
| 638 | + | |
| 639 | + rc = __wmi_send(wil, cmdid, buf, len); | |
| 640 | + if (rc) | |
| 641 | + goto out; | |
| 642 | + | |
| 643 | + wil->reply_id = reply_id; | |
| 644 | + wil->reply_buf = reply; | |
| 645 | + wil->reply_size = reply_size; | |
| 646 | + remain = wait_for_completion_timeout(&wil->wmi_ready, | |
| 647 | + msecs_to_jiffies(to_msec)); | |
| 648 | + if (0 == remain) { | |
| 649 | + wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n", | |
| 650 | + cmdid, reply_id, to_msec); | |
| 651 | + rc = -ETIME; | |
| 652 | + } else { | |
| 653 | + wil_dbg_WMI(wil, | |
| 654 | + "wmi_call(0x%04x->0x%04x) completed in %d msec\n", | |
| 655 | + cmdid, reply_id, | |
| 656 | + to_msec - jiffies_to_msecs(remain)); | |
| 657 | + } | |
| 658 | + wil->reply_id = 0; | |
| 659 | + wil->reply_buf = NULL; | |
| 660 | + wil->reply_size = 0; | |
| 661 | + out: | |
| 662 | + mutex_unlock(&wil->wmi_mutex); | |
| 663 | + | |
| 664 | + return rc; | |
| 665 | +} | |
| 666 | + | |
| 667 | +int wmi_echo(struct wil6210_priv *wil) | |
| 668 | +{ | |
| 669 | + struct wmi_echo_cmd cmd = { | |
| 670 | + .value = cpu_to_le32(0x12345678), | |
| 671 | + }; | |
| 672 | + | |
| 673 | + return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd), | |
| 674 | + WMI_ECHO_RSP_EVENTID, NULL, 0, 20); | |
| 675 | +} | |
| 676 | + | |
| 677 | +int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) | |
| 678 | +{ | |
| 679 | + struct wmi_set_mac_address_cmd cmd; | |
| 680 | + | |
| 681 | + memcpy(cmd.mac, addr, ETH_ALEN); | |
| 682 | + | |
| 683 | + wil_dbg_WMI(wil, "Set MAC %pM\n", addr); | |
| 684 | + | |
| 685 | + return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); | |
| 686 | +} | |
| 687 | + | |
| 688 | +int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype) | |
| 689 | +{ | |
| 690 | + struct wmi_bcon_ctrl_cmd cmd = { | |
| 691 | + .bcon_interval = cpu_to_le16(bi), | |
| 692 | + .network_type = wmi_nettype, | |
| 693 | + .disable_sec_offload = 1, | |
| 694 | + }; | |
| 695 | + | |
| 696 | + if (!wil->secure_pcp) | |
| 697 | + cmd.disable_sec = 1; | |
| 698 | + | |
| 699 | + return wmi_send(wil, WMI_BCON_CTRL_CMDID, &cmd, sizeof(cmd)); | |
| 700 | +} | |
| 701 | + | |
| 702 | +int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid) | |
| 703 | +{ | |
| 704 | + struct wmi_set_ssid_cmd cmd = { | |
| 705 | + .ssid_len = cpu_to_le32(ssid_len), | |
| 706 | + }; | |
| 707 | + | |
| 708 | + if (ssid_len > sizeof(cmd.ssid)) | |
| 709 | + return -EINVAL; | |
| 710 | + | |
| 711 | + memcpy(cmd.ssid, ssid, ssid_len); | |
| 712 | + | |
| 713 | + return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd)); | |
| 714 | +} | |
| 715 | + | |
| 716 | +int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid) | |
| 717 | +{ | |
| 718 | + int rc; | |
| 719 | + struct { | |
| 720 | + struct wil6210_mbox_hdr_wmi wmi; | |
| 721 | + struct wmi_set_ssid_cmd cmd; | |
| 722 | + } __packed reply; | |
| 723 | + int len; /* reply.cmd.ssid_len in CPU order */ | |
| 724 | + | |
| 725 | + rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID, | |
| 726 | + &reply, sizeof(reply), 20); | |
| 727 | + if (rc) | |
| 728 | + return rc; | |
| 729 | + | |
| 730 | + len = le32_to_cpu(reply.cmd.ssid_len); | |
| 731 | + if (len > sizeof(reply.cmd.ssid)) | |
| 732 | + return -EINVAL; | |
| 733 | + | |
| 734 | + *ssid_len = len; | |
| 735 | + memcpy(ssid, reply.cmd.ssid, len); | |
| 736 | + | |
| 737 | + return 0; | |
| 738 | +} | |
| 739 | + | |
| 740 | +int wmi_set_channel(struct wil6210_priv *wil, int channel) | |
| 741 | +{ | |
| 742 | + struct wmi_set_pcp_channel_cmd cmd = { | |
| 743 | + .channel = channel - 1, | |
| 744 | + }; | |
| 745 | + | |
| 746 | + return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd)); | |
| 747 | +} | |
| 748 | + | |
| 749 | +int wmi_get_channel(struct wil6210_priv *wil, int *channel) | |
| 750 | +{ | |
| 751 | + int rc; | |
| 752 | + struct { | |
| 753 | + struct wil6210_mbox_hdr_wmi wmi; | |
| 754 | + struct wmi_set_pcp_channel_cmd cmd; | |
| 755 | + } __packed reply; | |
| 756 | + | |
| 757 | + rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0, | |
| 758 | + WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20); | |
| 759 | + if (rc) | |
| 760 | + return rc; | |
| 761 | + | |
| 762 | + if (reply.cmd.channel > 3) | |
| 763 | + return -EINVAL; | |
| 764 | + | |
| 765 | + *channel = reply.cmd.channel + 1; | |
| 766 | + | |
| 767 | + return 0; | |
| 768 | +} | |
| 769 | + | |
| 770 | +int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb) | |
| 771 | +{ | |
| 772 | + struct wmi_eapol_tx_cmd *cmd; | |
| 773 | + struct ethhdr *eth; | |
| 774 | + u16 eapol_len = skb->len - ETH_HLEN; | |
| 775 | + void *eapol = skb->data + ETH_HLEN; | |
| 776 | + uint i; | |
| 777 | + int rc; | |
| 778 | + | |
| 779 | + skb_set_mac_header(skb, 0); | |
| 780 | + eth = eth_hdr(skb); | |
| 781 | + wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest); | |
| 782 | + for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { | |
| 783 | + if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0) | |
| 784 | + goto found_dest; | |
| 785 | + } | |
| 786 | + | |
| 787 | + return -EINVAL; | |
| 788 | + | |
| 789 | + found_dest: | |
| 790 | + /* find out eapol data & len */ | |
| 791 | + cmd = kzalloc(sizeof(*cmd) + eapol_len, GFP_KERNEL); | |
| 792 | + if (!cmd) | |
| 793 | + return -EINVAL; | |
| 794 | + | |
| 795 | + memcpy(cmd->dst_mac, eth->h_dest, ETH_ALEN); | |
| 796 | + cmd->eapol_len = cpu_to_le16(eapol_len); | |
| 797 | + memcpy(cmd->eapol, eapol, eapol_len); | |
| 798 | + rc = wmi_send(wil, WMI_EAPOL_TX_CMDID, cmd, sizeof(*cmd) + eapol_len); | |
| 799 | + kfree(cmd); | |
| 800 | + | |
| 801 | + return rc; | |
| 802 | +} | |
| 803 | + | |
| 804 | +int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index, | |
| 805 | + const void *mac_addr) | |
| 806 | +{ | |
| 807 | + struct wmi_delete_cipher_key_cmd cmd = { | |
| 808 | + .key_index = key_index, | |
| 809 | + }; | |
| 810 | + | |
| 811 | + if (mac_addr) | |
| 812 | + memcpy(cmd.mac, mac_addr, WMI_MAC_LEN); | |
| 813 | + | |
| 814 | + return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd)); | |
| 815 | +} | |
| 816 | + | |
| 817 | +int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, | |
| 818 | + const void *mac_addr, int key_len, const void *key) | |
| 819 | +{ | |
| 820 | + struct wmi_add_cipher_key_cmd cmd = { | |
| 821 | + .key_index = key_index, | |
| 822 | + .key_usage = WMI_KEY_USE_PAIRWISE, | |
| 823 | + .key_len = key_len, | |
| 824 | + }; | |
| 825 | + | |
| 826 | + if (!key || (key_len > sizeof(cmd.key))) | |
| 827 | + return -EINVAL; | |
| 828 | + | |
| 829 | + memcpy(cmd.key, key, key_len); | |
| 830 | + if (mac_addr) | |
| 831 | + memcpy(cmd.mac, mac_addr, WMI_MAC_LEN); | |
| 832 | + | |
| 833 | + return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd)); | |
| 834 | +} | |
| 835 | + | |
| 836 | +int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) | |
| 837 | +{ | |
| 838 | + int rc; | |
| 839 | + u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len; | |
| 840 | + struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); | |
| 841 | + if (!cmd) { | |
| 842 | + wil_err(wil, "kmalloc(%d) failed\n", len); | |
| 843 | + return -ENOMEM; | |
| 844 | + } | |
| 845 | + | |
| 846 | + cmd->mgmt_frm_type = type; | |
| 847 | + /* BUG: FW API define ieLen as u8. Will fix FW */ | |
| 848 | + cmd->ie_len = cpu_to_le16(ie_len); | |
| 849 | + memcpy(cmd->ie_info, ie, ie_len); | |
| 850 | + rc = wmi_send(wil, WMI_SET_APPIE_CMDID, &cmd, len); | |
| 851 | + kfree(cmd); | |
| 852 | + | |
| 853 | + return rc; | |
| 854 | +} | |
| 855 | + | |
| 856 | +void wmi_event_flush(struct wil6210_priv *wil) | |
| 857 | +{ | |
| 858 | + struct pending_wmi_event *evt, *t; | |
| 859 | + | |
| 860 | + wil_dbg_WMI(wil, "%s()\n", __func__); | |
| 861 | + | |
| 862 | + list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) { | |
| 863 | + list_del(&evt->list); | |
| 864 | + kfree(evt); | |
| 865 | + } | |
| 866 | +} | |
| 867 | + | |
| 868 | +static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id, | |
| 869 | + void *d, int len) | |
| 870 | +{ | |
| 871 | + uint i; | |
| 872 | + | |
| 873 | + for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) { | |
| 874 | + if (wmi_evt_handlers[i].eventid == id) { | |
| 875 | + wmi_evt_handlers[i].handler(wil, id, d, len); | |
| 876 | + return true; | |
| 877 | + } | |
| 878 | + } | |
| 879 | + | |
| 880 | + return false; | |
| 881 | +} | |
| 882 | + | |
| 883 | +static void wmi_event_handle(struct wil6210_priv *wil, | |
| 884 | + struct wil6210_mbox_hdr *hdr) | |
| 885 | +{ | |
| 886 | + u16 len = le16_to_cpu(hdr->len); | |
| 887 | + | |
| 888 | + if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) && | |
| 889 | + (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { | |
| 890 | + struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]); | |
| 891 | + void *evt_data = (void *)(&wmi[1]); | |
| 892 | + u16 id = le16_to_cpu(wmi->id); | |
| 893 | + /* check if someone waits for this event */ | |
| 894 | + if (wil->reply_id && wil->reply_id == id) { | |
| 895 | + if (wil->reply_buf) { | |
| 896 | + memcpy(wil->reply_buf, wmi, | |
| 897 | + min(len, wil->reply_size)); | |
| 898 | + } else { | |
| 899 | + wmi_evt_call_handler(wil, id, evt_data, | |
| 900 | + len - sizeof(*wmi)); | |
| 901 | + } | |
| 902 | + wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id); | |
| 903 | + complete(&wil->wmi_ready); | |
| 904 | + return; | |
| 905 | + } | |
| 906 | + /* unsolicited event */ | |
| 907 | + /* search for handler */ | |
| 908 | + if (!wmi_evt_call_handler(wil, id, evt_data, | |
| 909 | + len - sizeof(*wmi))) { | |
| 910 | + wil_err(wil, "Unhandled event 0x%04x\n", id); | |
| 911 | + } | |
| 912 | + } else { | |
| 913 | + wil_err(wil, "Unknown event type\n"); | |
| 914 | + print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1, | |
| 915 | + hdr, sizeof(*hdr) + len, true); | |
| 916 | + } | |
| 917 | +} | |
| 918 | + | |
| 919 | +/* | |
| 920 | + * Retrieve next WMI event from the pending list | |
| 921 | + */ | |
| 922 | +static struct list_head *next_wmi_ev(struct wil6210_priv *wil) | |
| 923 | +{ | |
| 924 | + ulong flags; | |
| 925 | + struct list_head *ret = NULL; | |
| 926 | + | |
| 927 | + spin_lock_irqsave(&wil->wmi_ev_lock, flags); | |
| 928 | + | |
| 929 | + if (!list_empty(&wil->pending_wmi_ev)) { | |
| 930 | + ret = wil->pending_wmi_ev.next; | |
| 931 | + list_del(ret); | |
| 932 | + } | |
| 933 | + | |
| 934 | + spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); | |
| 935 | + | |
| 936 | + return ret; | |
| 937 | +} | |
| 938 | + | |
| 939 | +/* | |
| 940 | + * Handler for the WMI events | |
| 941 | + */ | |
| 942 | +void wmi_event_worker(struct work_struct *work) | |
| 943 | +{ | |
| 944 | + struct wil6210_priv *wil = container_of(work, struct wil6210_priv, | |
| 945 | + wmi_event_worker); | |
| 946 | + struct pending_wmi_event *evt; | |
| 947 | + struct list_head *lh; | |
| 948 | + | |
| 949 | + while ((lh = next_wmi_ev(wil)) != NULL) { | |
| 950 | + evt = list_entry(lh, struct pending_wmi_event, list); | |
| 951 | + wmi_event_handle(wil, &evt->event.hdr); | |
| 952 | + kfree(evt); | |
| 953 | + } | |
| 954 | +} | |
| 955 | + | |
| 956 | +void wmi_connect_worker(struct work_struct *work) | |
| 957 | +{ | |
| 958 | + int rc; | |
| 959 | + struct wil6210_priv *wil = container_of(work, struct wil6210_priv, | |
| 960 | + wmi_connect_worker); | |
| 961 | + | |
| 962 | + if (wil->pending_connect_cid < 0) { | |
| 963 | + wil_err(wil, "No connection pending\n"); | |
| 964 | + return; | |
| 965 | + } | |
| 966 | + | |
| 967 | + wil_dbg_WMI(wil, "Configure for connection CID %d\n", | |
| 968 | + wil->pending_connect_cid); | |
| 969 | + | |
| 970 | + rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, | |
| 971 | + wil->pending_connect_cid, 0); | |
| 972 | + wil->pending_connect_cid = -1; | |
| 973 | + if (rc == 0) | |
| 974 | + wil_link_on(wil); | |
| 975 | +} | |
| @@ -0,0 +1,1116 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
| 3 | + * Copyright (c) 2006-2012 Wilocity . | |
| 4 | + * | |
| 5 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 6 | + * purpose with or without fee is hereby granted, provided that the above | |
| 7 | + * copyright notice and this permission notice appear in all copies. | |
| 8 | + * | |
| 9 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 10 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 11 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| 12 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 13 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 14 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| 15 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 16 | + */ | |
| 17 | + | |
| 18 | +/* | |
| 19 | + * This file contains the definitions of the WMI protocol specified in the | |
| 20 | + * Wireless Module Interface (WMI) for the Wilocity | |
| 21 | + * MARLON 60 Gigabit wireless solution. | |
| 22 | + * It includes definitions of all the commands and events. | |
| 23 | + * Commands are messages from the host to the WM. | |
| 24 | + * Events are messages from the WM to the host. | |
| 25 | + */ | |
| 26 | + | |
| 27 | +#ifndef __WILOCITY_WMI_H__ | |
| 28 | +#define __WILOCITY_WMI_H__ | |
| 29 | + | |
| 30 | +/* General */ | |
| 31 | + | |
| 32 | +#define WMI_MAC_LEN (6) | |
| 33 | +#define WMI_PROX_RANGE_NUM (3) | |
| 34 | + | |
| 35 | +/* List of Commands */ | |
| 36 | +enum wmi_command_id { | |
| 37 | + WMI_CONNECT_CMDID = 0x0001, | |
| 38 | + WMI_DISCONNECT_CMDID = 0x0003, | |
| 39 | + WMI_START_SCAN_CMDID = 0x0007, | |
| 40 | + WMI_SET_BSS_FILTER_CMDID = 0x0009, | |
| 41 | + WMI_SET_PROBED_SSID_CMDID = 0x000a, | |
| 42 | + WMI_SET_LISTEN_INT_CMDID = 0x000b, | |
| 43 | + WMI_BCON_CTRL_CMDID = 0x000f, | |
| 44 | + WMI_ADD_CIPHER_KEY_CMDID = 0x0016, | |
| 45 | + WMI_DELETE_CIPHER_KEY_CMDID = 0x0017, | |
| 46 | + WMI_SET_APPIE_CMDID = 0x003f, | |
| 47 | + WMI_GET_APPIE_CMDID = 0x0040, | |
| 48 | + WMI_SET_WSC_STATUS_CMDID = 0x0041, | |
| 49 | + WMI_PXMT_RANGE_CFG_CMDID = 0x0042, | |
| 50 | + WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043, | |
| 51 | + WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, | |
| 52 | + WMI_MEM_READ_CMDID = 0x0800, | |
| 53 | + WMI_MEM_WR_CMDID = 0x0801, | |
| 54 | + WMI_ECHO_CMDID = 0x0803, | |
| 55 | + WMI_DEEP_ECHO_CMDID = 0x0804, | |
| 56 | + WMI_CONFIG_MAC_CMDID = 0x0805, | |
| 57 | + WMI_CONFIG_PHY_DEBUG_CMDID = 0x0806, | |
| 58 | + WMI_ADD_STATION_CMDID = 0x0807, | |
| 59 | + WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x0808, | |
| 60 | + WMI_PHY_GET_STATISTICS_CMDID = 0x0809, | |
| 61 | + WMI_FS_TUNE_CMDID = 0x080a, | |
| 62 | + WMI_CORR_MEASURE_CMDID = 0x080b, | |
| 63 | + WMI_TEMP_SENSE_CMDID = 0x080e, | |
| 64 | + WMI_DC_CALIB_CMDID = 0x080f, | |
| 65 | + WMI_SEND_TONE_CMDID = 0x0810, | |
| 66 | + WMI_IQ_TX_CALIB_CMDID = 0x0811, | |
| 67 | + WMI_IQ_RX_CALIB_CMDID = 0x0812, | |
| 68 | + WMI_SET_UCODE_IDLE_CMDID = 0x0813, | |
| 69 | + WMI_SET_WORK_MODE_CMDID = 0x0815, | |
| 70 | + WMI_LO_LEAKAGE_CALIB_CMDID = 0x0816, | |
| 71 | + WMI_MARLON_R_ACTIVATE_CMDID = 0x0817, | |
| 72 | + WMI_MARLON_R_READ_CMDID = 0x0818, | |
| 73 | + WMI_MARLON_R_WRITE_CMDID = 0x0819, | |
| 74 | + WMI_MARLON_R_TXRX_SEL_CMDID = 0x081a, | |
| 75 | + MAC_IO_STATIC_PARAMS_CMDID = 0x081b, | |
| 76 | + MAC_IO_DYNAMIC_PARAMS_CMDID = 0x081c, | |
| 77 | + WMI_SILENT_RSSI_CALIB_CMDID = 0x081d, | |
| 78 | + WMI_CFG_RX_CHAIN_CMDID = 0x0820, | |
| 79 | + WMI_VRING_CFG_CMDID = 0x0821, | |
| 80 | + WMI_RX_ON_CMDID = 0x0822, | |
| 81 | + WMI_VRING_BA_EN_CMDID = 0x0823, | |
| 82 | + WMI_VRING_BA_DIS_CMDID = 0x0824, | |
| 83 | + WMI_RCP_ADDBA_RESP_CMDID = 0x0825, | |
| 84 | + WMI_RCP_DELBA_CMDID = 0x0826, | |
| 85 | + WMI_SET_SSID_CMDID = 0x0827, | |
| 86 | + WMI_GET_SSID_CMDID = 0x0828, | |
| 87 | + WMI_SET_PCP_CHANNEL_CMDID = 0x0829, | |
| 88 | + WMI_GET_PCP_CHANNEL_CMDID = 0x082a, | |
| 89 | + WMI_SW_TX_REQ_CMDID = 0x082b, | |
| 90 | + WMI_RX_OFF_CMDID = 0x082c, | |
| 91 | + WMI_READ_MAC_RXQ_CMDID = 0x0830, | |
| 92 | + WMI_READ_MAC_TXQ_CMDID = 0x0831, | |
| 93 | + WMI_WRITE_MAC_RXQ_CMDID = 0x0832, | |
| 94 | + WMI_WRITE_MAC_TXQ_CMDID = 0x0833, | |
| 95 | + WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x0834, | |
| 96 | + WMI_MLME_PUSH_CMDID = 0x0835, | |
| 97 | + WMI_BEAMFORMING_MGMT_CMDID = 0x0836, | |
| 98 | + WMI_BF_TXSS_MGMT_CMDID = 0x0837, | |
| 99 | + WMI_BF_SM_MGMT_CMDID = 0x0838, | |
| 100 | + WMI_BF_RXSS_MGMT_CMDID = 0x0839, | |
| 101 | + WMI_SET_SECTORS_CMDID = 0x0849, | |
| 102 | + WMI_MAINTAIN_PAUSE_CMDID = 0x0850, | |
| 103 | + WMI_MAINTAIN_RESUME_CMDID = 0x0851, | |
| 104 | + WMI_RS_MGMT_CMDID = 0x0852, | |
| 105 | + WMI_RF_MGMT_CMDID = 0x0853, | |
| 106 | + /* Performance monitoring commands */ | |
| 107 | + WMI_BF_CTRL_CMDID = 0x0862, | |
| 108 | + WMI_NOTIFY_REQ_CMDID = 0x0863, | |
| 109 | + WMI_GET_STATUS_CMDID = 0x0864, | |
| 110 | + WMI_UNIT_TEST_CMDID = 0x0900, | |
| 111 | + WMI_HICCUP_CMDID = 0x0901, | |
| 112 | + WMI_FLASH_READ_CMDID = 0x0902, | |
| 113 | + WMI_FLASH_WRITE_CMDID = 0x0903, | |
| 114 | + WMI_SECURITY_UNIT_TEST_CMDID = 0x0904, | |
| 115 | + | |
| 116 | + WMI_SET_MAC_ADDRESS_CMDID = 0xf003, | |
| 117 | + WMI_ABORT_SCAN_CMDID = 0xf007, | |
| 118 | + WMI_SET_PMK_CMDID = 0xf028, | |
| 119 | + | |
| 120 | + WMI_SET_PROMISCUOUS_MODE_CMDID = 0xf041, | |
| 121 | + WMI_GET_PMK_CMDID = 0xf048, | |
| 122 | + WMI_SET_PASSPHRASE_CMDID = 0xf049, | |
| 123 | + WMI_SEND_ASSOC_RES_CMDID = 0xf04a, | |
| 124 | + WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xf04b, | |
| 125 | + WMI_EAPOL_TX_CMDID = 0xf04c, | |
| 126 | + WMI_MAC_ADDR_REQ_CMDID = 0xf04d, | |
| 127 | + WMI_FW_VER_CMDID = 0xf04e, | |
| 128 | +}; | |
| 129 | + | |
| 130 | +/* | |
| 131 | + * Commands data structures | |
| 132 | + */ | |
| 133 | + | |
| 134 | +/* | |
| 135 | + * Frame Types | |
| 136 | + */ | |
| 137 | +enum wmi_mgmt_frame_type { | |
| 138 | + WMI_FRAME_BEACON = 0, | |
| 139 | + WMI_FRAME_PROBE_REQ = 1, | |
| 140 | + WMI_FRAME_PROBE_RESP = 2, | |
| 141 | + WMI_FRAME_ASSOC_REQ = 3, | |
| 142 | + WMI_FRAME_ASSOC_RESP = 4, | |
| 143 | + WMI_NUM_MGMT_FRAME, | |
| 144 | +}; | |
| 145 | + | |
| 146 | +/* | |
| 147 | + * WMI_CONNECT_CMDID | |
| 148 | + */ | |
| 149 | +enum wmi_network_type { | |
| 150 | + WMI_NETTYPE_INFRA = 0x01, | |
| 151 | + WMI_NETTYPE_ADHOC = 0x02, | |
| 152 | + WMI_NETTYPE_ADHOC_CREATOR = 0x04, | |
| 153 | + WMI_NETTYPE_AP = 0x10, | |
| 154 | + WMI_NETTYPE_P2P = 0x20, | |
| 155 | + WMI_NETTYPE_WBE = 0x40, /* PCIE over 60g */ | |
| 156 | +}; | |
| 157 | + | |
| 158 | +enum wmi_dot11_auth_mode { | |
| 159 | + WMI_AUTH11_OPEN = 0x01, | |
| 160 | + WMI_AUTH11_SHARED = 0x02, | |
| 161 | + WMI_AUTH11_LEAP = 0x04, | |
| 162 | + WMI_AUTH11_WSC = 0x08, | |
| 163 | +}; | |
| 164 | + | |
| 165 | +enum wmi_auth_mode { | |
| 166 | + WMI_AUTH_NONE = 0x01, | |
| 167 | + WMI_AUTH_WPA = 0x02, | |
| 168 | + WMI_AUTH_WPA2 = 0x04, | |
| 169 | + WMI_AUTH_WPA_PSK = 0x08, | |
| 170 | + WMI_AUTH_WPA2_PSK = 0x10, | |
| 171 | + WMI_AUTH_WPA_CCKM = 0x20, | |
| 172 | + WMI_AUTH_WPA2_CCKM = 0x40, | |
| 173 | +}; | |
| 174 | + | |
| 175 | +enum wmi_crypto_type { | |
| 176 | + WMI_CRYPT_NONE = 0x01, | |
| 177 | + WMI_CRYPT_WEP = 0x02, | |
| 178 | + WMI_CRYPT_TKIP = 0x04, | |
| 179 | + WMI_CRYPT_AES = 0x08, | |
| 180 | + WMI_CRYPT_AES_GCMP = 0x20, | |
| 181 | +}; | |
| 182 | + | |
| 183 | + | |
| 184 | +enum wmi_connect_ctrl_flag_bits { | |
| 185 | + WMI_CONNECT_ASSOC_POLICY_USER = 0x0001, | |
| 186 | + WMI_CONNECT_SEND_REASSOC = 0x0002, | |
| 187 | + WMI_CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004, | |
| 188 | + WMI_CONNECT_PROFILE_MATCH_DONE = 0x0008, | |
| 189 | + WMI_CONNECT_IGNORE_AAC_BEACON = 0x0010, | |
| 190 | + WMI_CONNECT_CSA_FOLLOW_BSS = 0x0020, | |
| 191 | + WMI_CONNECT_DO_WPA_OFFLOAD = 0x0040, | |
| 192 | + WMI_CONNECT_DO_NOT_DEAUTH = 0x0080, | |
| 193 | +}; | |
| 194 | + | |
| 195 | +#define WMI_MAX_SSID_LEN (32) | |
| 196 | + | |
| 197 | +struct wmi_connect_cmd { | |
| 198 | + u8 network_type; | |
| 199 | + u8 dot11_auth_mode; | |
| 200 | + u8 auth_mode; | |
| 201 | + u8 pairwise_crypto_type; | |
| 202 | + u8 pairwise_crypto_len; | |
| 203 | + u8 group_crypto_type; | |
| 204 | + u8 group_crypto_len; | |
| 205 | + u8 ssid_len; | |
| 206 | + u8 ssid[WMI_MAX_SSID_LEN]; | |
| 207 | + u8 channel; | |
| 208 | + u8 reserved0; | |
| 209 | + u8 bssid[WMI_MAC_LEN]; | |
| 210 | + __le32 ctrl_flags; | |
| 211 | + u8 dst_mac[WMI_MAC_LEN]; | |
| 212 | + u8 reserved1[2]; | |
| 213 | +} __packed; | |
| 214 | + | |
| 215 | + | |
| 216 | +/* | |
| 217 | + * WMI_RECONNECT_CMDID | |
| 218 | + */ | |
| 219 | +struct wmi_reconnect_cmd { | |
| 220 | + u8 channel; /* hint */ | |
| 221 | + u8 reserved; | |
| 222 | + u8 bssid[WMI_MAC_LEN]; /* mandatory if set */ | |
| 223 | +} __packed; | |
| 224 | + | |
| 225 | + | |
| 226 | +/* | |
| 227 | + * WMI_SET_PMK_CMDID | |
| 228 | + */ | |
| 229 | + | |
| 230 | +#define WMI_MIN_KEY_INDEX (0) | |
| 231 | +#define WMI_MAX_KEY_INDEX (3) | |
| 232 | +#define WMI_MAX_KEY_LEN (32) | |
| 233 | +#define WMI_PASSPHRASE_LEN (64) | |
| 234 | +#define WMI_PMK_LEN (32) | |
| 235 | + | |
| 236 | +struct wmi_set_pmk_cmd { | |
| 237 | + u8 pmk[WMI_PMK_LEN]; | |
| 238 | +} __packed; | |
| 239 | + | |
| 240 | + | |
| 241 | +/* | |
| 242 | + * WMI_SET_PASSPHRASE_CMDID | |
| 243 | + */ | |
| 244 | +struct wmi_set_passphrase_cmd { | |
| 245 | + u8 ssid[WMI_MAX_SSID_LEN]; | |
| 246 | + u8 passphrase[WMI_PASSPHRASE_LEN]; | |
| 247 | + u8 ssid_len; | |
| 248 | + u8 passphrase_len; | |
| 249 | +} __packed; | |
| 250 | + | |
| 251 | +/* | |
| 252 | + * WMI_ADD_CIPHER_KEY_CMDID | |
| 253 | + */ | |
| 254 | +enum wmi_key_usage { | |
| 255 | + WMI_KEY_USE_PAIRWISE = 0, | |
| 256 | + WMI_KEY_USE_GROUP = 1, | |
| 257 | + WMI_KEY_USE_TX = 2, /* default Tx Key - Static WEP only */ | |
| 258 | +}; | |
| 259 | + | |
| 260 | +struct wmi_add_cipher_key_cmd { | |
| 261 | + u8 key_index; | |
| 262 | + u8 key_type; | |
| 263 | + u8 key_usage; /* enum wmi_key_usage */ | |
| 264 | + u8 key_len; | |
| 265 | + u8 key_rsc[8]; /* key replay sequence counter */ | |
| 266 | + u8 key[WMI_MAX_KEY_LEN]; | |
| 267 | + u8 key_op_ctrl; /* Additional Key Control information */ | |
| 268 | + u8 mac[WMI_MAC_LEN]; | |
| 269 | +} __packed; | |
| 270 | + | |
| 271 | +/* | |
| 272 | + * WMI_DELETE_CIPHER_KEY_CMDID | |
| 273 | + */ | |
| 274 | +struct wmi_delete_cipher_key_cmd { | |
| 275 | + u8 key_index; | |
| 276 | + u8 mac[WMI_MAC_LEN]; | |
| 277 | +} __packed; | |
| 278 | + | |
| 279 | + | |
| 280 | +/* | |
| 281 | + * WMI_START_SCAN_CMDID | |
| 282 | + * | |
| 283 | + * Start L1 scan operation | |
| 284 | + * | |
| 285 | + * Returned events: | |
| 286 | + * - WMI_RX_MGMT_PACKET_EVENTID - for every probe resp. | |
| 287 | + * - WMI_SCAN_COMPLETE_EVENTID | |
| 288 | + */ | |
| 289 | +enum wmi_scan_type { | |
| 290 | + WMI_LONG_SCAN = 0, | |
| 291 | + WMI_SHORT_SCAN = 1, | |
| 292 | +}; | |
| 293 | + | |
| 294 | +struct wmi_start_scan_cmd { | |
| 295 | + u8 reserved[8]; | |
| 296 | + __le32 home_dwell_time; /* Max duration in the home channel(ms) */ | |
| 297 | + __le32 force_scan_interval; /* Time interval between scans (ms)*/ | |
| 298 | + u8 scan_type; /* wmi_scan_type */ | |
| 299 | + u8 num_channels; /* how many channels follow */ | |
| 300 | + struct { | |
| 301 | + u8 channel; | |
| 302 | + u8 reserved; | |
| 303 | + } channel_list[0]; /* channels ID's */ | |
| 304 | + /* 0 - 58320 MHz */ | |
| 305 | + /* 1 - 60480 MHz */ | |
| 306 | + /* 2 - 62640 MHz */ | |
| 307 | +} __packed; | |
| 308 | + | |
| 309 | +/* | |
| 310 | + * WMI_SET_PROBED_SSID_CMDID | |
| 311 | + */ | |
| 312 | +#define MAX_PROBED_SSID_INDEX (15) | |
| 313 | + | |
| 314 | +enum wmi_ssid_flag { | |
| 315 | + WMI_SSID_FLAG_DISABLE = 0, /* disables entry */ | |
| 316 | + WMI_SSID_FLAG_SPECIFIC = 1, /* probes specified ssid */ | |
| 317 | + WMI_SSID_FLAG_ANY = 2, /* probes for any ssid */ | |
| 318 | +}; | |
| 319 | + | |
| 320 | +struct wmi_probed_ssid_cmd { | |
| 321 | + u8 entry_index; /* 0 to MAX_PROBED_SSID_INDEX */ | |
| 322 | + u8 flag; /* enum wmi_ssid_flag */ | |
| 323 | + u8 ssid_len; | |
| 324 | + u8 ssid[WMI_MAX_SSID_LEN]; | |
| 325 | +} __packed; | |
| 326 | + | |
| 327 | +/* | |
| 328 | + * WMI_SET_APPIE_CMDID | |
| 329 | + * Add Application specified IE to a management frame | |
| 330 | + */ | |
| 331 | +struct wmi_set_appie_cmd { | |
| 332 | + u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */ | |
| 333 | + u8 reserved; | |
| 334 | + __le16 ie_len; /* Length of the IE to be added to MGMT frame */ | |
| 335 | + u8 ie_info[0]; | |
| 336 | +} __packed; | |
| 337 | + | |
| 338 | +#define WMI_MAX_IE_LEN (1024) | |
| 339 | + | |
| 340 | +struct wmi_pxmt_range_cfg_cmd { | |
| 341 | + u8 dst_mac[WMI_MAC_LEN]; | |
| 342 | + __le16 range; | |
| 343 | +} __packed; | |
| 344 | + | |
| 345 | +struct wmi_pxmt_snr2_range_cfg_cmd { | |
| 346 | + s8 snr2range_arr[WMI_PROX_RANGE_NUM-1]; | |
| 347 | +} __packed; | |
| 348 | + | |
| 349 | +/* | |
| 350 | + * WMI_RF_MGMT_CMDID | |
| 351 | + */ | |
| 352 | +enum wmi_rf_mgmt_type { | |
| 353 | + WMI_RF_MGMT_W_DISABLE = 0, | |
| 354 | + WMI_RF_MGMT_W_ENABLE = 1, | |
| 355 | + WMI_RF_MGMT_GET_STATUS = 2, | |
| 356 | +}; | |
| 357 | + | |
| 358 | +struct wmi_rf_mgmt_cmd { | |
| 359 | + __le32 rf_mgmt_type; | |
| 360 | +} __packed; | |
| 361 | + | |
| 362 | +/* | |
| 363 | + * WMI_SET_SSID_CMDID | |
| 364 | + */ | |
| 365 | +struct wmi_set_ssid_cmd { | |
| 366 | + __le32 ssid_len; | |
| 367 | + u8 ssid[WMI_MAX_SSID_LEN]; | |
| 368 | +} __packed; | |
| 369 | + | |
| 370 | +/* | |
| 371 | + * WMI_SET_PCP_CHANNEL_CMDID | |
| 372 | + */ | |
| 373 | +struct wmi_set_pcp_channel_cmd { | |
| 374 | + u8 channel; | |
| 375 | + u8 reserved[3]; | |
| 376 | +} __packed; | |
| 377 | + | |
| 378 | +/* | |
| 379 | + * WMI_BCON_CTRL_CMDID | |
| 380 | + */ | |
| 381 | +struct wmi_bcon_ctrl_cmd { | |
| 382 | + __le16 bcon_interval; | |
| 383 | + __le16 frag_num; | |
| 384 | + __le64 ss_mask; | |
| 385 | + u8 network_type; | |
| 386 | + u8 reserved; | |
| 387 | + u8 disable_sec_offload; | |
| 388 | + u8 disable_sec; | |
| 389 | +} __packed; | |
| 390 | + | |
| 391 | +/* | |
| 392 | + * WMI_SW_TX_REQ_CMDID | |
| 393 | + */ | |
| 394 | +struct wmi_sw_tx_req_cmd { | |
| 395 | + u8 dst_mac[WMI_MAC_LEN]; | |
| 396 | + __le16 len; | |
| 397 | + u8 payload[0]; | |
| 398 | +} __packed; | |
| 399 | + | |
| 400 | +/* | |
| 401 | + * WMI_VRING_CFG_CMDID | |
| 402 | + */ | |
| 403 | + | |
| 404 | +struct wmi_sw_ring_cfg { | |
| 405 | + __le64 ring_mem_base; | |
| 406 | + __le16 ring_size; | |
| 407 | + __le16 max_mpdu_size; | |
| 408 | +} __packed; | |
| 409 | + | |
| 410 | +struct wmi_vring_cfg_schd { | |
| 411 | + __le16 priority; | |
| 412 | + __le16 timeslot_us; | |
| 413 | +} __packed; | |
| 414 | + | |
| 415 | +enum wmi_vring_cfg_encap_trans_type { | |
| 416 | + WMI_VRING_ENC_TYPE_802_3 = 0, | |
| 417 | + WMI_VRING_ENC_TYPE_NATIVE_WIFI = 1, | |
| 418 | +}; | |
| 419 | + | |
| 420 | +enum wmi_vring_cfg_ds_cfg { | |
| 421 | + WMI_VRING_DS_PBSS = 0, | |
| 422 | + WMI_VRING_DS_STATION = 1, | |
| 423 | + WMI_VRING_DS_AP = 2, | |
| 424 | + WMI_VRING_DS_ADDR4 = 3, | |
| 425 | +}; | |
| 426 | + | |
| 427 | +enum wmi_vring_cfg_nwifi_ds_trans_type { | |
| 428 | + WMI_NWIFI_TX_TRANS_MODE_NO = 0, | |
| 429 | + WMI_NWIFI_TX_TRANS_MODE_AP2PBSS = 1, | |
| 430 | + WMI_NWIFI_TX_TRANS_MODE_STA2PBSS = 2, | |
| 431 | +}; | |
| 432 | + | |
| 433 | +enum wmi_vring_cfg_schd_params_priority { | |
| 434 | + WMI_SCH_PRIO_REGULAR = 0, | |
| 435 | + WMI_SCH_PRIO_HIGH = 1, | |
| 436 | +}; | |
| 437 | + | |
| 438 | +struct wmi_vring_cfg { | |
| 439 | + struct wmi_sw_ring_cfg tx_sw_ring; | |
| 440 | + u8 ringid; /* 0-23 vrings */ | |
| 441 | + | |
| 442 | + #define CIDXTID_CID_POS (0) | |
| 443 | + #define CIDXTID_CID_LEN (4) | |
| 444 | + #define CIDXTID_CID_MSK (0xF) | |
| 445 | + #define CIDXTID_TID_POS (4) | |
| 446 | + #define CIDXTID_TID_LEN (4) | |
| 447 | + #define CIDXTID_TID_MSK (0xF0) | |
| 448 | + u8 cidxtid; | |
| 449 | + | |
| 450 | + u8 encap_trans_type; | |
| 451 | + u8 ds_cfg; /* 802.3 DS cfg */ | |
| 452 | + u8 nwifi_ds_trans_type; | |
| 453 | + | |
| 454 | + #define VRING_CFG_MAC_CTRL_LIFETIME_EN_POS (0) | |
| 455 | + #define VRING_CFG_MAC_CTRL_LIFETIME_EN_LEN (1) | |
| 456 | + #define VRING_CFG_MAC_CTRL_LIFETIME_EN_MSK (0x1) | |
| 457 | + #define VRING_CFG_MAC_CTRL_AGGR_EN_POS (1) | |
| 458 | + #define VRING_CFG_MAC_CTRL_AGGR_EN_LEN (1) | |
| 459 | + #define VRING_CFG_MAC_CTRL_AGGR_EN_MSK (0x2) | |
| 460 | + u8 mac_ctrl; | |
| 461 | + | |
| 462 | + #define VRING_CFG_TO_RESOLUTION_VALUE_POS (0) | |
| 463 | + #define VRING_CFG_TO_RESOLUTION_VALUE_LEN (6) | |
| 464 | + #define VRING_CFG_TO_RESOLUTION_VALUE_MSK (0x3F) | |
| 465 | + u8 to_resolution; | |
| 466 | + u8 agg_max_wsize; | |
| 467 | + struct wmi_vring_cfg_schd schd_params; | |
| 468 | +} __packed; | |
| 469 | + | |
| 470 | +enum wmi_vring_cfg_cmd_action { | |
| 471 | + WMI_VRING_CMD_ADD = 0, | |
| 472 | + WMI_VRING_CMD_MODIFY = 1, | |
| 473 | + WMI_VRING_CMD_DELETE = 2, | |
| 474 | +}; | |
| 475 | + | |
| 476 | +struct wmi_vring_cfg_cmd { | |
| 477 | + __le32 action; | |
| 478 | + struct wmi_vring_cfg vring_cfg; | |
| 479 | +} __packed; | |
| 480 | + | |
| 481 | +/* | |
| 482 | + * WMI_VRING_BA_EN_CMDID | |
| 483 | + */ | |
| 484 | +struct wmi_vring_ba_en_cmd { | |
| 485 | + u8 ringid; | |
| 486 | + u8 agg_max_wsize; | |
| 487 | + __le16 ba_timeout; | |
| 488 | +} __packed; | |
| 489 | + | |
| 490 | +/* | |
| 491 | + * WMI_VRING_BA_DIS_CMDID | |
| 492 | + */ | |
| 493 | +struct wmi_vring_ba_dis_cmd { | |
| 494 | + u8 ringid; | |
| 495 | + u8 reserved; | |
| 496 | + __le16 reason; | |
| 497 | +} __packed; | |
| 498 | + | |
| 499 | +/* | |
| 500 | + * WMI_NOTIFY_REQ_CMDID | |
| 501 | + */ | |
| 502 | +struct wmi_notify_req_cmd { | |
| 503 | + u8 cid; | |
| 504 | + u8 reserved[3]; | |
| 505 | + __le32 interval_usec; | |
| 506 | +} __packed; | |
| 507 | + | |
| 508 | +/* | |
| 509 | + * WMI_CFG_RX_CHAIN_CMDID | |
| 510 | + */ | |
| 511 | +enum wmi_sniffer_cfg_mode { | |
| 512 | + WMI_SNIFFER_OFF = 0, | |
| 513 | + WMI_SNIFFER_ON = 1, | |
| 514 | +}; | |
| 515 | + | |
| 516 | +enum wmi_sniffer_cfg_phy_info_mode { | |
| 517 | + WMI_SNIFFER_PHY_INFO_DISABLED = 0, | |
| 518 | + WMI_SNIFFER_PHY_INFO_ENABLED = 1, | |
| 519 | +}; | |
| 520 | + | |
| 521 | +enum wmi_sniffer_cfg_phy_support { | |
| 522 | + WMI_SNIFFER_CP = 0, | |
| 523 | + WMI_SNIFFER_DP = 1, | |
| 524 | + WMI_SNIFFER_BOTH_PHYS = 2, | |
| 525 | +}; | |
| 526 | + | |
| 527 | +struct wmi_sniffer_cfg { | |
| 528 | + __le32 mode; /* enum wmi_sniffer_cfg_mode */ | |
| 529 | + __le32 phy_info_mode; /* enum wmi_sniffer_cfg_phy_info_mode */ | |
| 530 | + __le32 phy_support; /* enum wmi_sniffer_cfg_phy_support */ | |
| 531 | + u8 channel; | |
| 532 | + u8 reserved[3]; | |
| 533 | +} __packed; | |
| 534 | + | |
| 535 | +enum wmi_cfg_rx_chain_cmd_action { | |
| 536 | + WMI_RX_CHAIN_ADD = 0, | |
| 537 | + WMI_RX_CHAIN_DEL = 1, | |
| 538 | +}; | |
| 539 | + | |
| 540 | +enum wmi_cfg_rx_chain_cmd_decap_trans_type { | |
| 541 | + WMI_DECAP_TYPE_802_3 = 0, | |
| 542 | + WMI_DECAP_TYPE_NATIVE_WIFI = 1, | |
| 543 | +}; | |
| 544 | + | |
| 545 | +enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type { | |
| 546 | + WMI_NWIFI_RX_TRANS_MODE_NO = 0, | |
| 547 | + WMI_NWIFI_RX_TRANS_MODE_PBSS2AP = 1, | |
| 548 | + WMI_NWIFI_RX_TRANS_MODE_PBSS2STA = 2, | |
| 549 | +}; | |
| 550 | + | |
| 551 | +struct wmi_cfg_rx_chain_cmd { | |
| 552 | + __le32 action; | |
| 553 | + struct wmi_sw_ring_cfg rx_sw_ring; | |
| 554 | + u8 mid; | |
| 555 | + u8 decap_trans_type; | |
| 556 | + | |
| 557 | + #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_POS (0) | |
| 558 | + #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_LEN (1) | |
| 559 | + #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_MSK (0x1) | |
| 560 | + u8 l2_802_3_offload_ctrl; | |
| 561 | + | |
| 562 | + #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_POS (0) | |
| 563 | + #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_LEN (1) | |
| 564 | + #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_MSK (0x1) | |
| 565 | + #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_POS (1) | |
| 566 | + #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_LEN (1) | |
| 567 | + #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_MSK (0x2) | |
| 568 | + u8 l2_nwifi_offload_ctrl; | |
| 569 | + | |
| 570 | + u8 vlan_id; | |
| 571 | + u8 nwifi_ds_trans_type; | |
| 572 | + | |
| 573 | + #define L3_L4_CTRL_IPV4_CHECKSUM_EN_POS (0) | |
| 574 | + #define L3_L4_CTRL_IPV4_CHECKSUM_EN_LEN (1) | |
| 575 | + #define L3_L4_CTRL_IPV4_CHECKSUM_EN_MSK (0x1) | |
| 576 | + #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS (1) | |
| 577 | + #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_LEN (1) | |
| 578 | + #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_MSK (0x2) | |
| 579 | + u8 l3_l4_ctrl; | |
| 580 | + | |
| 581 | + #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_POS (0) | |
| 582 | + #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_LEN (1) | |
| 583 | + #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_MSK (0x1) | |
| 584 | + #define RING_CTRL_OVERRIDE_WB_THRSH_POS (1) | |
| 585 | + #define RING_CTRL_OVERRIDE_WB_THRSH_LEN (1) | |
| 586 | + #define RING_CTRL_OVERRIDE_WB_THRSH_MSK (0x2) | |
| 587 | + #define RING_CTRL_OVERRIDE_ITR_THRSH_POS (2) | |
| 588 | + #define RING_CTRL_OVERRIDE_ITR_THRSH_LEN (1) | |
| 589 | + #define RING_CTRL_OVERRIDE_ITR_THRSH_MSK (0x4) | |
| 590 | + #define RING_CTRL_OVERRIDE_HOST_THRSH_POS (3) | |
| 591 | + #define RING_CTRL_OVERRIDE_HOST_THRSH_LEN (1) | |
| 592 | + #define RING_CTRL_OVERRIDE_HOST_THRSH_MSK (0x8) | |
| 593 | + u8 ring_ctrl; | |
| 594 | + | |
| 595 | + __le16 prefetch_thrsh; | |
| 596 | + __le16 wb_thrsh; | |
| 597 | + __le32 itr_value; | |
| 598 | + __le16 host_thrsh; | |
| 599 | + u8 reserved[2]; | |
| 600 | + struct wmi_sniffer_cfg sniffer_cfg; | |
| 601 | +} __packed; | |
| 602 | + | |
| 603 | +/* | |
| 604 | + * WMI_RCP_ADDBA_RESP_CMDID | |
| 605 | + */ | |
| 606 | +struct wmi_rcp_addba_resp_cmd { | |
| 607 | + | |
| 608 | + #define CIDXTID_CID_POS (0) | |
| 609 | + #define CIDXTID_CID_LEN (4) | |
| 610 | + #define CIDXTID_CID_MSK (0xF) | |
| 611 | + #define CIDXTID_TID_POS (4) | |
| 612 | + #define CIDXTID_TID_LEN (4) | |
| 613 | + #define CIDXTID_TID_MSK (0xF0) | |
| 614 | + u8 cidxtid; | |
| 615 | + | |
| 616 | + u8 dialog_token; | |
| 617 | + __le16 status_code; | |
| 618 | + __le16 ba_param_set; /* ieee80211_ba_parameterset field to send */ | |
| 619 | + __le16 ba_timeout; | |
| 620 | +} __packed; | |
| 621 | + | |
| 622 | +/* | |
| 623 | + * WMI_RCP_DELBA_CMDID | |
| 624 | + */ | |
| 625 | +struct wmi_rcp_delba_cmd { | |
| 626 | + | |
| 627 | + #define CIDXTID_CID_POS (0) | |
| 628 | + #define CIDXTID_CID_LEN (4) | |
| 629 | + #define CIDXTID_CID_MSK (0xF) | |
| 630 | + #define CIDXTID_TID_POS (4) | |
| 631 | + #define CIDXTID_TID_LEN (4) | |
| 632 | + #define CIDXTID_TID_MSK (0xF0) | |
| 633 | + u8 cidxtid; | |
| 634 | + | |
| 635 | + u8 reserved; | |
| 636 | + __le16 reason; | |
| 637 | +} __packed; | |
| 638 | + | |
| 639 | +/* | |
| 640 | + * WMI_RCP_ADDBA_REQ_CMDID | |
| 641 | + */ | |
| 642 | +struct wmi_rcp_addba_req_cmd { | |
| 643 | + | |
| 644 | + #define CIDXTID_CID_POS (0) | |
| 645 | + #define CIDXTID_CID_LEN (4) | |
| 646 | + #define CIDXTID_CID_MSK (0xF) | |
| 647 | + #define CIDXTID_TID_POS (4) | |
| 648 | + #define CIDXTID_TID_LEN (4) | |
| 649 | + #define CIDXTID_TID_MSK (0xF0) | |
| 650 | + u8 cidxtid; | |
| 651 | + | |
| 652 | + u8 dialog_token; | |
| 653 | + /* ieee80211_ba_parameterset field as it received */ | |
| 654 | + __le16 ba_param_set; | |
| 655 | + __le16 ba_timeout; | |
| 656 | + /* ieee80211_ba_seqstrl field as it received */ | |
| 657 | + __le16 ba_seq_ctrl; | |
| 658 | +} __packed; | |
| 659 | + | |
| 660 | +/* | |
| 661 | + * WMI_SET_MAC_ADDRESS_CMDID | |
| 662 | + */ | |
| 663 | +struct wmi_set_mac_address_cmd { | |
| 664 | + u8 mac[WMI_MAC_LEN]; | |
| 665 | + u8 reserved[2]; | |
| 666 | +} __packed; | |
| 667 | + | |
| 668 | + | |
| 669 | +/* | |
| 670 | +* WMI_EAPOL_TX_CMDID | |
| 671 | +*/ | |
| 672 | +struct wmi_eapol_tx_cmd { | |
| 673 | + u8 dst_mac[WMI_MAC_LEN]; | |
| 674 | + __le16 eapol_len; | |
| 675 | + u8 eapol[0]; | |
| 676 | +} __packed; | |
| 677 | + | |
| 678 | +/* | |
| 679 | + * WMI_ECHO_CMDID | |
| 680 | + * | |
| 681 | + * Check FW is alive | |
| 682 | + * | |
| 683 | + * WMI_DEEP_ECHO_CMDID | |
| 684 | + * | |
| 685 | + * Check FW and ucode are alive | |
| 686 | + * | |
| 687 | + * Returned event: WMI_ECHO_RSP_EVENTID | |
| 688 | + * same event for both commands | |
| 689 | + */ | |
| 690 | +struct wmi_echo_cmd { | |
| 691 | + __le32 value; | |
| 692 | +} __packed; | |
| 693 | + | |
| 694 | +/* | |
| 695 | + * WMI Events | |
| 696 | + */ | |
| 697 | + | |
| 698 | +/* | |
| 699 | + * List of Events (target to host) | |
| 700 | + */ | |
| 701 | +enum wmi_event_id { | |
| 702 | + WMI_IMM_RSP_EVENTID = 0x0000, | |
| 703 | + WMI_READY_EVENTID = 0x1001, | |
| 704 | + WMI_CONNECT_EVENTID = 0x1002, | |
| 705 | + WMI_DISCONNECT_EVENTID = 0x1003, | |
| 706 | + WMI_SCAN_COMPLETE_EVENTID = 0x100a, | |
| 707 | + WMI_REPORT_STATISTICS_EVENTID = 0x100b, | |
| 708 | + WMI_RD_MEM_RSP_EVENTID = 0x1800, | |
| 709 | + WMI_FW_READY_EVENTID = 0x1801, | |
| 710 | + WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x0200, | |
| 711 | + WMI_ECHO_RSP_EVENTID = 0x1803, | |
| 712 | + WMI_CONFIG_MAC_DONE_EVENTID = 0x1805, | |
| 713 | + WMI_CONFIG_PHY_DEBUG_DONE_EVENTID = 0x1806, | |
| 714 | + WMI_ADD_STATION_DONE_EVENTID = 0x1807, | |
| 715 | + WMI_ADD_DEBUG_TX_PCKT_DONE_EVENTID = 0x1808, | |
| 716 | + WMI_PHY_GET_STATISTICS_EVENTID = 0x1809, | |
| 717 | + WMI_FS_TUNE_DONE_EVENTID = 0x180a, | |
| 718 | + WMI_CORR_MEASURE_DONE_EVENTID = 0x180b, | |
| 719 | + WMI_TEMP_SENSE_DONE_EVENTID = 0x180e, | |
| 720 | + WMI_DC_CALIB_DONE_EVENTID = 0x180f, | |
| 721 | + WMI_IQ_TX_CALIB_DONE_EVENTID = 0x1811, | |
| 722 | + WMI_IQ_RX_CALIB_DONE_EVENTID = 0x1812, | |
| 723 | + WMI_SET_WORK_MODE_DONE_EVENTID = 0x1815, | |
| 724 | + WMI_LO_LEAKAGE_CALIB_DONE_EVENTID = 0x1816, | |
| 725 | + WMI_MARLON_R_ACTIVATE_DONE_EVENTID = 0x1817, | |
| 726 | + WMI_MARLON_R_READ_DONE_EVENTID = 0x1818, | |
| 727 | + WMI_MARLON_R_WRITE_DONE_EVENTID = 0x1819, | |
| 728 | + WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181a, | |
| 729 | + WMI_SILENT_RSSI_CALIB_DONE_EVENTID = 0x181d, | |
| 730 | + | |
| 731 | + WMI_CFG_RX_CHAIN_DONE_EVENTID = 0x1820, | |
| 732 | + WMI_VRING_CFG_DONE_EVENTID = 0x1821, | |
| 733 | + WMI_RX_ON_DONE_EVENTID = 0x1822, | |
| 734 | + WMI_BA_STATUS_EVENTID = 0x1823, | |
| 735 | + WMI_RCP_ADDBA_REQ_EVENTID = 0x1824, | |
| 736 | + WMI_ADDBA_RESP_SENT_EVENTID = 0x1825, | |
| 737 | + WMI_DELBA_EVENTID = 0x1826, | |
| 738 | + WMI_GET_SSID_EVENTID = 0x1828, | |
| 739 | + WMI_GET_PCP_CHANNEL_EVENTID = 0x182a, | |
| 740 | + WMI_SW_TX_COMPLETE_EVENTID = 0x182b, | |
| 741 | + WMI_RX_OFF_DONE_EVENTID = 0x182c, | |
| 742 | + | |
| 743 | + WMI_READ_MAC_RXQ_EVENTID = 0x1830, | |
| 744 | + WMI_READ_MAC_TXQ_EVENTID = 0x1831, | |
| 745 | + WMI_WRITE_MAC_RXQ_EVENTID = 0x1832, | |
| 746 | + WMI_WRITE_MAC_TXQ_EVENTID = 0x1833, | |
| 747 | + WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834, | |
| 748 | + | |
| 749 | + WMI_BEAFORMING_MGMT_DONE_EVENTID = 0x1836, | |
| 750 | + WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837, | |
| 751 | + WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, | |
| 752 | + WMI_RS_MGMT_DONE_EVENTID = 0x1852, | |
| 753 | + WMI_RF_MGMT_STATUS_EVENTID = 0x1853, | |
| 754 | + WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, | |
| 755 | + WMI_RX_MGMT_PACKET_EVENTID = 0x1840, | |
| 756 | + | |
| 757 | + /* Performance monitoring events */ | |
| 758 | + WMI_DATA_PORT_OPEN_EVENTID = 0x1860, | |
| 759 | + WMI_WBE_LINKDOWN_EVENTID = 0x1861, | |
| 760 | + | |
| 761 | + WMI_BF_CTRL_DONE_EVENTID = 0x1862, | |
| 762 | + WMI_NOTIFY_REQ_DONE_EVENTID = 0x1863, | |
| 763 | + WMI_GET_STATUS_DONE_EVENTID = 0x1864, | |
| 764 | + | |
| 765 | + WMI_UNIT_TEST_EVENTID = 0x1900, | |
| 766 | + WMI_FLASH_READ_DONE_EVENTID = 0x1902, | |
| 767 | + WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, | |
| 768 | + | |
| 769 | + WMI_SET_CHANNEL_EVENTID = 0x9000, | |
| 770 | + WMI_ASSOC_REQ_EVENTID = 0x9001, | |
| 771 | + WMI_EAPOL_RX_EVENTID = 0x9002, | |
| 772 | + WMI_MAC_ADDR_RESP_EVENTID = 0x9003, | |
| 773 | + WMI_FW_VER_EVENTID = 0x9004, | |
| 774 | +}; | |
| 775 | + | |
| 776 | +/* | |
| 777 | + * Events data structures | |
| 778 | + */ | |
| 779 | + | |
| 780 | +/* | |
| 781 | + * WMI_RF_MGMT_STATUS_EVENTID | |
| 782 | + */ | |
| 783 | +enum wmi_rf_status { | |
| 784 | + WMI_RF_ENABLED = 0, | |
| 785 | + WMI_RF_DISABLED_HW = 1, | |
| 786 | + WMI_RF_DISABLED_SW = 2, | |
| 787 | + WMI_RF_DISABLED_HW_SW = 3, | |
| 788 | +}; | |
| 789 | + | |
| 790 | +struct wmi_rf_mgmt_status_event { | |
| 791 | + __le32 rf_status; | |
| 792 | +} __packed; | |
| 793 | + | |
| 794 | +/* | |
| 795 | + * WMI_GET_STATUS_DONE_EVENTID | |
| 796 | + */ | |
| 797 | +struct wmi_get_status_done_event { | |
| 798 | + __le32 is_associated; | |
| 799 | + u8 cid; | |
| 800 | + u8 reserved0[3]; | |
| 801 | + u8 bssid[WMI_MAC_LEN]; | |
| 802 | + u8 channel; | |
| 803 | + u8 reserved1; | |
| 804 | + u8 network_type; | |
| 805 | + u8 reserved2[3]; | |
| 806 | + __le32 ssid_len; | |
| 807 | + u8 ssid[WMI_MAX_SSID_LEN]; | |
| 808 | + __le32 rf_status; | |
| 809 | + __le32 is_secured; | |
| 810 | +} __packed; | |
| 811 | + | |
| 812 | +/* | |
| 813 | + * WMI_FW_VER_EVENTID | |
| 814 | + */ | |
| 815 | +struct wmi_fw_ver_event { | |
| 816 | + u8 major; | |
| 817 | + u8 minor; | |
| 818 | + __le16 subminor; | |
| 819 | + __le16 build; | |
| 820 | +} __packed; | |
| 821 | + | |
| 822 | +/* | |
| 823 | +* WMI_MAC_ADDR_RESP_EVENTID | |
| 824 | +*/ | |
| 825 | +struct wmi_mac_addr_resp_event { | |
| 826 | + u8 mac[WMI_MAC_LEN]; | |
| 827 | + u8 auth_mode; | |
| 828 | + u8 crypt_mode; | |
| 829 | + __le32 offload_mode; | |
| 830 | +} __packed; | |
| 831 | + | |
| 832 | +/* | |
| 833 | +* WMI_EAPOL_RX_EVENTID | |
| 834 | +*/ | |
| 835 | +struct wmi_eapol_rx_event { | |
| 836 | + u8 src_mac[WMI_MAC_LEN]; | |
| 837 | + __le16 eapol_len; | |
| 838 | + u8 eapol[0]; | |
| 839 | +} __packed; | |
| 840 | + | |
| 841 | +/* | |
| 842 | +* WMI_READY_EVENTID | |
| 843 | +*/ | |
| 844 | +enum wmi_phy_capability { | |
| 845 | + WMI_11A_CAPABILITY = 1, | |
| 846 | + WMI_11G_CAPABILITY = 2, | |
| 847 | + WMI_11AG_CAPABILITY = 3, | |
| 848 | + WMI_11NA_CAPABILITY = 4, | |
| 849 | + WMI_11NG_CAPABILITY = 5, | |
| 850 | + WMI_11NAG_CAPABILITY = 6, | |
| 851 | + WMI_11AD_CAPABILITY = 7, | |
| 852 | + WMI_11N_CAPABILITY_OFFSET = WMI_11NA_CAPABILITY - WMI_11A_CAPABILITY, | |
| 853 | +}; | |
| 854 | + | |
| 855 | +struct wmi_ready_event { | |
| 856 | + __le32 sw_version; | |
| 857 | + __le32 abi_version; | |
| 858 | + u8 mac[WMI_MAC_LEN]; | |
| 859 | + u8 phy_capability; /* enum wmi_phy_capability */ | |
| 860 | + u8 reserved; | |
| 861 | +} __packed; | |
| 862 | + | |
| 863 | +/* | |
| 864 | + * WMI_NOTIFY_REQ_DONE_EVENTID | |
| 865 | + */ | |
| 866 | +struct wmi_notify_req_done_event { | |
| 867 | + __le32 status; | |
| 868 | + __le64 tsf; | |
| 869 | + __le32 snr_val; | |
| 870 | + __le32 tx_tpt; | |
| 871 | + __le32 tx_goodput; | |
| 872 | + __le32 rx_goodput; | |
| 873 | + __le16 bf_mcs; | |
| 874 | + __le16 my_rx_sector; | |
| 875 | + __le16 my_tx_sector; | |
| 876 | + __le16 other_rx_sector; | |
| 877 | + __le16 other_tx_sector; | |
| 878 | + __le16 range; | |
| 879 | +} __packed; | |
| 880 | + | |
| 881 | +/* | |
| 882 | + * WMI_CONNECT_EVENTID | |
| 883 | + */ | |
| 884 | +struct wmi_connect_event { | |
| 885 | + u8 channel; | |
| 886 | + u8 reserved0; | |
| 887 | + u8 bssid[WMI_MAC_LEN]; | |
| 888 | + __le16 listen_interval; | |
| 889 | + __le16 beacon_interval; | |
| 890 | + u8 network_type; | |
| 891 | + u8 reserved1[3]; | |
| 892 | + u8 beacon_ie_len; | |
| 893 | + u8 assoc_req_len; | |
| 894 | + u8 assoc_resp_len; | |
| 895 | + u8 cid; | |
| 896 | + u8 reserved2[3]; | |
| 897 | + u8 assoc_info[0]; | |
| 898 | +} __packed; | |
| 899 | + | |
| 900 | +/* | |
| 901 | + * WMI_DISCONNECT_EVENTID | |
| 902 | + */ | |
| 903 | +enum wmi_disconnect_reason { | |
| 904 | + WMI_DIS_REASON_NO_NETWORK_AVAIL = 1, | |
| 905 | + WMI_DIS_REASON_LOST_LINK = 2, /* bmiss */ | |
| 906 | + WMI_DIS_REASON_DISCONNECT_CMD = 3, | |
| 907 | + WMI_DIS_REASON_BSS_DISCONNECTED = 4, | |
| 908 | + WMI_DIS_REASON_AUTH_FAILED = 5, | |
| 909 | + WMI_DIS_REASON_ASSOC_FAILED = 6, | |
| 910 | + WMI_DIS_REASON_NO_RESOURCES_AVAIL = 7, | |
| 911 | + WMI_DIS_REASON_CSERV_DISCONNECT = 8, | |
| 912 | + WMI_DIS_REASON_INVALID_PROFILE = 10, | |
| 913 | + WMI_DIS_REASON_DOT11H_CHANNEL_SWITCH = 11, | |
| 914 | + WMI_DIS_REASON_PROFILE_MISMATCH = 12, | |
| 915 | + WMI_DIS_REASON_CONNECTION_EVICTED = 13, | |
| 916 | + WMI_DIS_REASON_IBSS_MERGE = 14, | |
| 917 | +}; | |
| 918 | + | |
| 919 | +struct wmi_disconnect_event { | |
| 920 | + __le16 protocol_reason_status; /* reason code, see 802.11 spec. */ | |
| 921 | + u8 bssid[WMI_MAC_LEN]; /* set if known */ | |
| 922 | + u8 disconnect_reason; /* see wmi_disconnect_reason_e */ | |
| 923 | + u8 assoc_resp_len; | |
| 924 | + u8 assoc_info[0]; | |
| 925 | +} __packed; | |
| 926 | + | |
| 927 | +/* | |
| 928 | + * WMI_SCAN_COMPLETE_EVENTID | |
| 929 | + */ | |
| 930 | +struct wmi_scan_complete_event { | |
| 931 | + __le32 status; | |
| 932 | +} __packed; | |
| 933 | + | |
| 934 | +/* | |
| 935 | + * WMI_BA_STATUS_EVENTID | |
| 936 | + */ | |
| 937 | +enum wmi_vring_ba_status { | |
| 938 | + WMI_BA_AGREED = 0, | |
| 939 | + WMI_BA_NON_AGREED = 1, | |
| 940 | +}; | |
| 941 | + | |
| 942 | +struct wmi_vring_ba_status_event { | |
| 943 | + __le16 status; | |
| 944 | + u8 reserved[2]; | |
| 945 | + u8 ringid; | |
| 946 | + u8 agg_wsize; | |
| 947 | + __le16 ba_timeout; | |
| 948 | +} __packed; | |
| 949 | + | |
| 950 | +/* | |
| 951 | + * WMI_DELBA_EVENTID | |
| 952 | + */ | |
| 953 | +struct wmi_delba_event { | |
| 954 | + | |
| 955 | + #define CIDXTID_CID_POS (0) | |
| 956 | + #define CIDXTID_CID_LEN (4) | |
| 957 | + #define CIDXTID_CID_MSK (0xF) | |
| 958 | + #define CIDXTID_TID_POS (4) | |
| 959 | + #define CIDXTID_TID_LEN (4) | |
| 960 | + #define CIDXTID_TID_MSK (0xF0) | |
| 961 | + u8 cidxtid; | |
| 962 | + | |
| 963 | + u8 from_initiator; | |
| 964 | + __le16 reason; | |
| 965 | +} __packed; | |
| 966 | + | |
| 967 | +/* | |
| 968 | + * WMI_VRING_CFG_DONE_EVENTID | |
| 969 | + */ | |
| 970 | +enum wmi_vring_cfg_done_event_status { | |
| 971 | + WMI_VRING_CFG_SUCCESS = 0, | |
| 972 | + WMI_VRING_CFG_FAILURE = 1, | |
| 973 | +}; | |
| 974 | + | |
| 975 | +struct wmi_vring_cfg_done_event { | |
| 976 | + u8 ringid; | |
| 977 | + u8 status; | |
| 978 | + u8 reserved[2]; | |
| 979 | + __le32 tx_vring_tail_ptr; | |
| 980 | +} __packed; | |
| 981 | + | |
| 982 | +/* | |
| 983 | + * WMI_ADDBA_RESP_SENT_EVENTID | |
| 984 | + */ | |
| 985 | +enum wmi_rcp_addba_resp_sent_event_status { | |
| 986 | + WMI_ADDBA_SUCCESS = 0, | |
| 987 | + WMI_ADDBA_FAIL = 1, | |
| 988 | +}; | |
| 989 | + | |
| 990 | +struct wmi_rcp_addba_resp_sent_event { | |
| 991 | + | |
| 992 | + #define CIDXTID_CID_POS (0) | |
| 993 | + #define CIDXTID_CID_LEN (4) | |
| 994 | + #define CIDXTID_CID_MSK (0xF) | |
| 995 | + #define CIDXTID_TID_POS (4) | |
| 996 | + #define CIDXTID_TID_LEN (4) | |
| 997 | + #define CIDXTID_TID_MSK (0xF0) | |
| 998 | + u8 cidxtid; | |
| 999 | + | |
| 1000 | + u8 reserved; | |
| 1001 | + __le16 status; | |
| 1002 | +} __packed; | |
| 1003 | + | |
| 1004 | +/* | |
| 1005 | + * WMI_RCP_ADDBA_REQ_EVENTID | |
| 1006 | + */ | |
| 1007 | +struct wmi_rcp_addba_req_event { | |
| 1008 | + | |
| 1009 | + #define CIDXTID_CID_POS (0) | |
| 1010 | + #define CIDXTID_CID_LEN (4) | |
| 1011 | + #define CIDXTID_CID_MSK (0xF) | |
| 1012 | + #define CIDXTID_TID_POS (4) | |
| 1013 | + #define CIDXTID_TID_LEN (4) | |
| 1014 | + #define CIDXTID_TID_MSK (0xF0) | |
| 1015 | + u8 cidxtid; | |
| 1016 | + | |
| 1017 | + u8 dialog_token; | |
| 1018 | + __le16 ba_param_set; /* ieee80211_ba_parameterset as it received */ | |
| 1019 | + __le16 ba_timeout; | |
| 1020 | + __le16 ba_seq_ctrl; /* ieee80211_ba_seqstrl field as it received */ | |
| 1021 | +} __packed; | |
| 1022 | + | |
| 1023 | +/* | |
| 1024 | + * WMI_CFG_RX_CHAIN_DONE_EVENTID | |
| 1025 | + */ | |
| 1026 | +enum wmi_cfg_rx_chain_done_event_status { | |
| 1027 | + WMI_CFG_RX_CHAIN_SUCCESS = 1, | |
| 1028 | +}; | |
| 1029 | + | |
| 1030 | +struct wmi_cfg_rx_chain_done_event { | |
| 1031 | + __le32 rx_ring_tail_ptr; /* Rx V-Ring Tail pointer */ | |
| 1032 | + __le32 status; | |
| 1033 | +} __packed; | |
| 1034 | + | |
| 1035 | +/* | |
| 1036 | + * WMI_WBE_LINKDOWN_EVENTID | |
| 1037 | + */ | |
| 1038 | +enum wmi_wbe_link_down_event_reason { | |
| 1039 | + WMI_WBE_REASON_USER_REQUEST = 0, | |
| 1040 | + WMI_WBE_REASON_RX_DISASSOC = 1, | |
| 1041 | + WMI_WBE_REASON_BAD_PHY_LINK = 2, | |
| 1042 | +}; | |
| 1043 | + | |
| 1044 | +struct wmi_wbe_link_down_event { | |
| 1045 | + u8 cid; | |
| 1046 | + u8 reserved[3]; | |
| 1047 | + __le32 reason; | |
| 1048 | +} __packed; | |
| 1049 | + | |
| 1050 | +/* | |
| 1051 | + * WMI_DATA_PORT_OPEN_EVENTID | |
| 1052 | + */ | |
| 1053 | +struct wmi_data_port_open_event { | |
| 1054 | + u8 cid; | |
| 1055 | + u8 reserved[3]; | |
| 1056 | +} __packed; | |
| 1057 | + | |
| 1058 | +/* | |
| 1059 | + * WMI_GET_PCP_CHANNEL_EVENTID | |
| 1060 | + */ | |
| 1061 | +struct wmi_get_pcp_channel_event { | |
| 1062 | + u8 channel; | |
| 1063 | + u8 reserved[3]; | |
| 1064 | +} __packed; | |
| 1065 | + | |
| 1066 | +/* | |
| 1067 | + * WMI_SW_TX_COMPLETE_EVENTID | |
| 1068 | + */ | |
| 1069 | +enum wmi_sw_tx_status { | |
| 1070 | + WMI_TX_SW_STATUS_SUCCESS = 0, | |
| 1071 | + WMI_TX_SW_STATUS_FAILED_NO_RESOURCES = 1, | |
| 1072 | + WMI_TX_SW_STATUS_FAILED_TX = 2, | |
| 1073 | +}; | |
| 1074 | + | |
| 1075 | +struct wmi_sw_tx_complete_event { | |
| 1076 | + u8 status; /* enum wmi_sw_tx_status */ | |
| 1077 | + u8 reserved[3]; | |
| 1078 | +} __packed; | |
| 1079 | + | |
| 1080 | +/* | |
| 1081 | + * WMI_GET_SSID_EVENTID | |
| 1082 | + */ | |
| 1083 | +struct wmi_get_ssid_event { | |
| 1084 | + __le32 ssid_len; | |
| 1085 | + u8 ssid[WMI_MAX_SSID_LEN]; | |
| 1086 | +} __packed; | |
| 1087 | + | |
| 1088 | +/* | |
| 1089 | + * WMI_RX_MGMT_PACKET_EVENTID | |
| 1090 | + */ | |
| 1091 | +struct wmi_rx_mgmt_info { | |
| 1092 | + u8 mcs; | |
| 1093 | + s8 snr; | |
| 1094 | + __le16 range; | |
| 1095 | + __le16 stype; | |
| 1096 | + __le16 status; | |
| 1097 | + __le32 len; | |
| 1098 | + u8 qid; | |
| 1099 | + u8 mid; | |
| 1100 | + u8 cid; | |
| 1101 | + u8 channel; /* From Radio MNGR */ | |
| 1102 | +} __packed; | |
| 1103 | + | |
| 1104 | +struct wmi_rx_mgmt_packet_event { | |
| 1105 | + struct wmi_rx_mgmt_info info; | |
| 1106 | + u8 payload[0]; | |
| 1107 | +} __packed; | |
| 1108 | + | |
| 1109 | +/* | |
| 1110 | + * WMI_ECHO_RSP_EVENTID | |
| 1111 | + */ | |
| 1112 | +struct wmi_echo_event { | |
| 1113 | + __le32 echoed_value; | |
| 1114 | +} __packed; | |
| 1115 | + | |
| 1116 | +#endif /* __WILOCITY_WMI_H__ */ | |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <linux/hw_random.h> |
| 8 | 8 | #include <linux/bcma/bcma.h> |
| 9 | 9 | #include <linux/ssb/ssb.h> |
| 10 | +#include <linux/completion.h> | |
| 10 | 11 | #include <net/mac80211.h> |
| 11 | 12 | |
| 12 | 13 | #include "debugfs.h" |
| @@ -722,6 +723,10 @@ enum b43_firmware_file_type { · 709 unmodified lines | ||
| 722 | 723 | struct b43_request_fw_context { |
| 723 | 724 | /* The device we are requesting the fw for. */ |
| 724 | 725 | struct b43_wldev *dev; |
| 726 | + /* a completion event structure needed if this call is asynchronous */ | |
| 727 | + struct completion fw_load_complete; | |
| 728 | + /* a pointer to the firmware object */ | |
| 729 | + const struct firmware *blob; | |
| 725 | 730 | /* The type of firmware to request. */ |
| 726 | 731 | enum b43_firmware_file_type req_type; |
| 727 | 732 | /* Error messages for each firmware type. */ |
| @@ -2088,11 +2088,18 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error) · 2087 unmodified lines | ||
| 2088 | 2088 | b43warn(wl, text); |
| 2089 | 2089 | } |
| 2090 | 2090 | |
| 2091 | +static void b43_fw_cb(const struct firmware *firmware, void *context) | |
| 2092 | +{ | |
| 2093 | + struct b43_request_fw_context *ctx = context; | |
| 2094 | + | |
| 2095 | + ctx->blob = firmware; | |
| 2096 | + complete(&ctx->fw_load_complete); | |
| 2097 | +} | |
| 2098 | + | |
| 2091 | 2099 | int b43_do_request_fw(struct b43_request_fw_context *ctx, |
| 2092 | 2100 | const char *name, |
| 2093 | − struct b43_firmware_file *fw) | |
| 2101 | + struct b43_firmware_file *fw, bool async) | |
| 2094 | 2102 | { |
| 2095 | − const struct firmware *blob; | |
| 2096 | 2103 | struct b43_fw_header *hdr; |
| 2097 | 2104 | u32 size; |
| 2098 | 2105 | int err; |
| @@ -2131,11 +2138,31 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, · 32 unmodified lines | ||
| 2131 | 2138 | B43_WARN_ON(1); |
| 2132 | 2139 | return -ENOSYS; |
| 2133 | 2140 | } |
| 2134 | − err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev); | |
| 2141 | + if (async) { | |
| 2142 | + /* do this part asynchronously */ | |
| 2143 | + init_completion(&ctx->fw_load_complete); | |
| 2144 | + err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, | |
| 2145 | + ctx->dev->dev->dev, GFP_KERNEL, | |
| 2146 | + ctx, b43_fw_cb); | |
| 2147 | + if (err < 0) { | |
| 2148 | + pr_err("Unable to load firmware\n"); | |
| 2149 | + return err; | |
| 2150 | + } | |
| 2151 | + /* stall here until fw ready */ | |
| 2152 | + wait_for_completion(&ctx->fw_load_complete); | |
| 2153 | + if (ctx->blob) | |
| 2154 | + goto fw_ready; | |
| 2155 | + /* On some ARM systems, the async request will fail, but the next sync | |
| 2156 | + * request works. For this reason, we dall through here | |
| 2157 | + */ | |
| 2158 | + } | |
| 2159 | + err = request_firmware(&ctx->blob, ctx->fwname, | |
| 2160 | + ctx->dev->dev->dev); | |
| 2135 | 2161 | if (err == -ENOENT) { |
| 2136 | 2162 | snprintf(ctx->errors[ctx->req_type], |
| 2137 | 2163 | sizeof(ctx->errors[ctx->req_type]), |
| 2138 | − "Firmware file \"%s\" not found\n", ctx->fwname); | |
| 2164 | + "Firmware file \"%s\" not found\n", | |
| 2165 | + ctx->fwname); | |
| 2139 | 2166 | return err; |
| 2140 | 2167 | } else if (err) { |
| 2141 | 2168 | snprintf(ctx->errors[ctx->req_type], |
| @@ -2144,14 +2171,15 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, · 2 unmodified lines | ||
| 2144 | 2171 | ctx->fwname, err); |
| 2145 | 2172 | return err; |
| 2146 | 2173 | } |
| 2147 | − if (blob->size < sizeof(struct b43_fw_header)) | |
| 2174 | +fw_ready: | |
| 2175 | + if (ctx->blob->size < sizeof(struct b43_fw_header)) | |
| 2148 | 2176 | goto err_format; |
| 2149 | − hdr = (struct b43_fw_header *)(blob->data); | |
| 2177 | + hdr = (struct b43_fw_header *)(ctx->blob->data); | |
| 2150 | 2178 | switch (hdr->type) { |
| 2151 | 2179 | case B43_FW_TYPE_UCODE: |
| 2152 | 2180 | case B43_FW_TYPE_PCM: |
| 2153 | 2181 | size = be32_to_cpu(hdr->size); |
| 2154 | − if (size != blob->size - sizeof(struct b43_fw_header)) | |
| 2182 | + if (size != ctx->blob->size - sizeof(struct b43_fw_header)) | |
| 2155 | 2183 | goto err_format; |
| 2156 | 2184 | /* fallthrough */ |
| 2157 | 2185 | case B43_FW_TYPE_IV: |
| @@ -2162,7 +2190,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, · 4 unmodified lines | ||
| 2162 | 2190 | goto err_format; |
| 2163 | 2191 | } |
| 2164 | 2192 | |
| 2165 | − fw->data = blob; | |
| 2193 | + fw->data = ctx->blob; | |
| 2166 | 2194 | fw->filename = name; |
| 2167 | 2195 | fw->type = ctx->req_type; |
| 2168 | 2196 | |
| @@ -2172,7 +2200,7 @@ err_format: · 3 unmodified lines | ||
| 2172 | 2200 | snprintf(ctx->errors[ctx->req_type], |
| 2173 | 2201 | sizeof(ctx->errors[ctx->req_type]), |
| 2174 | 2202 | "Firmware file \"%s\" format error.\n", ctx->fwname); |
| 2175 | − release_firmware(blob); | |
| 2203 | + release_firmware(ctx->blob); | |
| 2176 | 2204 | |
| 2177 | 2205 | return -EPROTO; |
| 2178 | 2206 | } |
| @@ -2223,7 +2251,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) · 44 unmodified lines | ||
| 2223 | 2251 | goto err_no_ucode; |
| 2224 | 2252 | } |
| 2225 | 2253 | } |
| 2226 | − err = b43_do_request_fw(ctx, filename, &fw->ucode); | |
| 2254 | + err = b43_do_request_fw(ctx, filename, &fw->ucode, true); | |
| 2227 | 2255 | if (err) |
| 2228 | 2256 | goto err_load; |
| 2229 | 2257 | |
| @@ -2235,7 +2263,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) · 5 unmodified lines | ||
| 2235 | 2263 | else |
| 2236 | 2264 | goto err_no_pcm; |
| 2237 | 2265 | fw->pcm_request_failed = false; |
| 2238 | − err = b43_do_request_fw(ctx, filename, &fw->pcm); | |
| 2266 | + err = b43_do_request_fw(ctx, filename, &fw->pcm, false); | |
| 2239 | 2267 | if (err == -ENOENT) { |
| 2240 | 2268 | /* We did not find a PCM file? Not fatal, but |
| 2241 | 2269 | * core rev <= 10 must do without hwcrypto then. */ |
| @@ -2296,7 +2324,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) · 54 unmodified lines | ||
| 2296 | 2324 | default: |
| 2297 | 2325 | goto err_no_initvals; |
| 2298 | 2326 | } |
| 2299 | − err = b43_do_request_fw(ctx, filename, &fw->initvals); | |
| 2327 | + err = b43_do_request_fw(ctx, filename, &fw->initvals, false); | |
| 2300 | 2328 | if (err) |
| 2301 | 2329 | goto err_load; |
| 2302 | 2330 | |
| @@ -2355,7 +2383,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) · 52 unmodified lines | ||
| 2355 | 2383 | default: |
| 2356 | 2384 | goto err_no_initvals; |
| 2357 | 2385 | } |
| 2358 | − err = b43_do_request_fw(ctx, filename, &fw->initvals_band); | |
| 2386 | + err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false); | |
| 2359 | 2387 | if (err) |
| 2360 | 2388 | goto err_load; |
| 2361 | 2389 | |
| @@ -137,9 +137,8 @@ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on); · 136 unmodified lines | ||
| 137 | 137 | |
| 138 | 138 | |
| 139 | 139 | struct b43_request_fw_context; |
| 140 | −int b43_do_request_fw(struct b43_request_fw_context *ctx, | |
| 141 | − const char *name, | |
| 142 | − struct b43_firmware_file *fw); | |
| 140 | +int b43_do_request_fw(struct b43_request_fw_context *ctx, const char *name, | |
| 141 | + struct b43_firmware_file *fw, bool async); | |
| 143 | 142 | void b43_do_release_fw(struct b43_firmware_file *fw); |
| 144 | 143 | |
| 145 | 144 | #endif /* B43_MAIN_H_ */ |
| @@ -3226,8 +3226,6 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( · 3225 unmodified lines | ||
| 3226 | 3226 | { |
| 3227 | 3227 | struct nphy_gain_ctl_workaround_entry *e; |
| 3228 | 3228 | u8 phy_idx; |
| 3229 | − u8 tr_iso = ghz5 ? dev->dev->bus_sprom->fem.ghz5.tr_iso : | |
| 3230 | − dev->dev->bus_sprom->fem.ghz2.tr_iso; | |
| 3231 | 3229 | |
| 3232 | 3230 | if (!ghz5 && dev->phy.rev >= 6 && dev->phy.radio_rev == 11) |
| 3233 | 3231 | return &nphy_gain_ctl_wa_phy6_radio11_ghz2; |
| @@ -3249,6 +3247,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( · 15 unmodified lines | ||
| 3249 | 3247 | !b43_channel_type_is_40mhz(dev->phy.channel_type)) |
| 3250 | 3248 | e->cliplo_gain = 0x2d; |
| 3251 | 3249 | } else if (!ghz5 && dev->phy.rev >= 5) { |
| 3250 | + static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a, | |
| 3251 | + 0x106c, 0x1074, 0x107c, 0x207c}; | |
| 3252 | + u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso; | |
| 3253 | + | |
| 3252 | 3254 | if (ext_lna) { |
| 3253 | 3255 | e->rfseq_init[0] &= ~0x4000; |
| 3254 | 3256 | e->rfseq_init[1] &= ~0x4000; |
| @@ -3256,26 +3258,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( · 1 unmodified line | ||
| 3256 | 3258 | e->rfseq_init[3] &= ~0x4000; |
| 3257 | 3259 | e->init_gain &= ~0x4000; |
| 3258 | 3260 | } |
| 3259 | − switch (tr_iso) { | |
| 3260 | − case 0: | |
| 3261 | − e->cliplo_gain = 0x0062; | |
| 3262 | − case 1: | |
| 3263 | − e->cliplo_gain = 0x0064; | |
| 3264 | − case 2: | |
| 3265 | − e->cliplo_gain = 0x006a; | |
| 3266 | − case 3: | |
| 3267 | − e->cliplo_gain = 0x106a; | |
| 3268 | − case 4: | |
| 3269 | − e->cliplo_gain = 0x106c; | |
| 3270 | − case 5: | |
| 3271 | − e->cliplo_gain = 0x1074; | |
| 3272 | − case 6: | |
| 3273 | − e->cliplo_gain = 0x107c; | |
| 3274 | − case 7: | |
| 3275 | − e->cliplo_gain = 0x207c; | |
| 3276 | − default: | |
| 3277 | − e->cliplo_gain = 0x106a; | |
| 3278 | − } | |
| 3261 | + if (tr_iso > 7) | |
| 3262 | + tr_iso = 3; | |
| 3263 | + e->cliplo_gain = gain_data[tr_iso]; | |
| 3264 | + | |
| 3279 | 3265 | } else if (ghz5 && dev->phy.rev == 4 && ext_lna) { |
| 3280 | 3266 | e->rfseq_init[0] &= ~0x4000; |
| 3281 | 3267 | e->rfseq_init[1] &= ~0x4000; |
| @@ -15,8 +15,6 @@ · 14 unmodified lines | ||
| 15 | 15 | */ |
| 16 | 16 | /* ****************** SDIO CARD Interface Functions **************************/ |
| 17 | 17 | |
| 18 | −#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 19 | − | |
| 20 | 18 | #include <linux/types.h> |
| 21 | 19 | #include <linux/netdevice.h> |
| 22 | 20 | #include <linux/export.h> |
| @@ -14,8 +14,6 @@ · 13 unmodified lines | ||
| 14 | 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 15 | 15 | */ |
| 16 | 16 | |
| 17 | −#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 18 | − | |
| 19 | 17 | #include <linux/types.h> |
| 20 | 18 | #include <linux/netdevice.h> |
| 21 | 19 | #include <linux/mmc/sdio.h> |
| @@ -39,6 +39,7 @@ · 38 unmodified lines | ||
| 39 | 39 | #define BRCMF_C_GET_BSSID 23 |
| 40 | 40 | #define BRCMF_C_GET_SSID 25 |
| 41 | 41 | #define BRCMF_C_SET_SSID 26 |
| 42 | +#define BRCMF_C_TERMINATED 28 | |
| 42 | 43 | #define BRCMF_C_GET_CHANNEL 29 |
| 43 | 44 | #define BRCMF_C_SET_CHANNEL 30 |
| 44 | 45 | #define BRCMF_C_GET_SRL 31 |
| @@ -480,36 +481,14 @@ struct brcmf_pub { · 435 unmodified lines | ||
| 480 | 481 | unsigned long drv_version; /* Version of dongle-resident driver */ |
| 481 | 482 | u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */ |
| 482 | 483 | |
| 483 | − /* Additional stats for the bus level */ | |
| 484 | − | |
| 485 | 484 | /* Multicast data packets sent to dongle */ |
| 486 | 485 | unsigned long tx_multicast; |
| 487 | − /* Packets flushed due to unscheduled sendup thread */ | |
| 488 | − unsigned long rx_flushed; | |
| 489 | − /* Number of times dpc scheduled by watchdog timer */ | |
| 490 | − unsigned long wd_dpc_sched; | |
| 491 | − | |
| 492 | − /* Number of flow control pkts recvd */ | |
| 493 | − unsigned long fc_packets; | |
| 494 | − | |
| 495 | − /* Last error return */ | |
| 496 | − int bcmerror; | |
| 497 | − | |
| 498 | − /* Last error from dongle */ | |
| 499 | − int dongle_error; | |
| 500 | − | |
| 501 | − /* Suspend disable flag flag */ | |
| 502 | − int suspend_disable_flag; /* "1" to disable all extra powersaving | |
| 503 | − during suspend */ | |
| 504 | − int in_suspend; /* flag set to 1 when early suspend called */ | |
| 505 | − int dtim_skip; /* dtim skip , default 0 means wake each dtim */ | |
| 506 | 486 | |
| 507 | 487 | struct brcmf_if *iflist[BRCMF_MAX_IFS]; |
| 508 | 488 | |
| 509 | 489 | struct mutex proto_block; |
| 510 | 490 | unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; |
| 511 | 491 | |
| 512 | − u8 macvalue[ETH_ALEN]; | |
| 513 | 492 | atomic_t pend_8021x_cnt; |
| 514 | 493 | wait_queue_head_t pend_8021x_wait; |
| 515 | 494 | |
| @@ -519,11 +498,6 @@ struct brcmf_pub { · 3 unmodified lines | ||
| 519 | 498 | #endif |
| 520 | 499 | }; |
| 521 | 500 | |
| 522 | −struct bcmevent_name { | |
| 523 | − uint event; | |
| 524 | − const char *name; | |
| 525 | −}; | |
| 526 | − | |
| 527 | 501 | struct brcmf_if_event { |
| 528 | 502 | u8 ifidx; |
| 529 | 503 | u8 action; |
| @@ -557,13 +531,6 @@ struct brcmf_if { · 27 unmodified lines | ||
| 557 | 531 | u8 mac_addr[ETH_ALEN]; |
| 558 | 532 | }; |
| 559 | 533 | |
| 560 | −static inline s32 brcmf_ndev_bssidx(struct net_device *ndev) | |
| 561 | −{ | |
| 562 | − struct brcmf_if *ifp = netdev_priv(ndev); | |
| 563 | − return ifp->bssidx; | |
| 564 | −} | |
| 565 | − | |
| 566 | −extern const struct bcmevent_name bcmevent_names[]; | |
| 567 | 534 | |
| 568 | 535 | extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); |
| 569 | 536 | |
| @@ -576,6 +543,10 @@ extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, · 6 unmodified lines | ||
| 576 | 543 | extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, |
| 577 | 544 | void *buf, uint len); |
| 578 | 545 | |
| 546 | +/* Remove any protocol-specific data header. */ | |
| 547 | +extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, | |
| 548 | + struct sk_buff *rxp); | |
| 549 | + | |
| 579 | 550 | extern int brcmf_net_attach(struct brcmf_if *ifp); |
| 580 | 551 | extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, |
| 581 | 552 | s32 bssidx, char *name, u8 *mac_addr); |
| @@ -130,31 +130,18 @@ int brcmf_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint len) · 129 unmodified lines | ||
| 130 | 130 | * interface functions from common layer |
| 131 | 131 | */ |
| 132 | 132 | |
| 133 | −/* Remove any protocol-specific data header. */ | |
| 134 | −extern int brcmf_proto_hdrpull(struct device *dev, int *ifidx, | |
| 135 | − struct sk_buff *rxp); | |
| 136 | − | |
| 137 | 133 | extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, |
| 138 | 134 | struct sk_buff *pkt, int prec); |
| 139 | 135 | |
| 140 | 136 | /* Receive frame for delivery to OS. Callee disposes of rxp. */ |
| 141 | −extern void brcmf_rx_frame(struct device *dev, u8 ifidx, | |
| 142 | − struct sk_buff_head *rxlist); | |
| 143 | −static inline void brcmf_rx_packet(struct device *dev, int ifidx, | |
| 144 | − struct sk_buff *pkt) | |
| 145 | −{ | |
| 146 | − struct sk_buff_head q; | |
| 147 | − | |
| 148 | − skb_queue_head_init(&q); | |
| 149 | − skb_queue_tail(&q, pkt); | |
| 150 | − brcmf_rx_frame(dev, ifidx, &q); | |
| 151 | −} | |
| 137 | +extern void brcmf_rx_frames(struct device *dev, struct sk_buff_head *rxlist); | |
| 152 | 138 | |
| 153 | 139 | /* Indication from bus module regarding presence/insertion of dongle. */ |
| 154 | 140 | extern int brcmf_attach(uint bus_hdrlen, struct device *dev); |
| 155 | 141 | /* Indication from bus module regarding removal/absence of dongle */ |
| 156 | 142 | extern void brcmf_detach(struct device *dev); |
| 157 | − | |
| 143 | +/* Indication from bus module that dongle should be reset */ | |
| 144 | +extern void brcmf_dev_reset(struct device *dev); | |
| 158 | 145 | /* Indication from bus module to change flow-control state */ |
| 159 | 146 | extern void brcmf_txflowblock(struct device *dev, bool state); |
| 160 | 147 | |
| @@ -19,8 +19,6 @@ · 18 unmodified lines | ||
| 19 | 19 | * For certain dcmd codes, the dongle interprets string data from the host. |
| 20 | 20 | ******************************************************************************/ |
| 21 | 21 | |
| 22 | −#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 23 | − | |
| 24 | 22 | #include <linux/types.h> |
| 25 | 23 | #include <linux/netdevice.h> |
| 26 | 24 | |
| @@ -94,8 +92,6 @@ struct brcmf_proto_bdc_header { · 67 unmodified lines | ||
| 94 | 92 | |
| 95 | 93 | struct brcmf_proto { |
| 96 | 94 | u16 reqid; |
| 97 | − u8 pending; | |
| 98 | − u32 lastcmd; | |
| 99 | 95 | u8 bus_header[BUS_HEADER_LEN]; |
| 100 | 96 | struct brcmf_proto_cdc_dcmd msg; |
| 101 | 97 | unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN]; |
| @@ -107,7 +103,7 @@ static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) · 5 unmodified lines | ||
| 107 | 103 | int len = le32_to_cpu(prot->msg.len) + |
| 108 | 104 | sizeof(struct brcmf_proto_cdc_dcmd); |
| 109 | 105 | |
| 110 | − brcmf_dbg(TRACE, "Enter\n"); | |
| 106 | + brcmf_dbg(CDC, "Enter\n"); | |
| 111 | 107 | |
| 112 | 108 | /* NOTE : cdc->msg.len holds the desired length of the buffer to be |
| 113 | 109 | * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area |
| @@ -125,7 +121,7 @@ static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) · 11 unmodified lines | ||
| 125 | 121 | int ret; |
| 126 | 122 | struct brcmf_proto *prot = drvr->prot; |
| 127 | 123 | |
| 128 | − brcmf_dbg(TRACE, "Enter\n"); | |
| 124 | + brcmf_dbg(CDC, "Enter\n"); | |
| 129 | 125 | len += sizeof(struct brcmf_proto_cdc_dcmd); |
| 130 | 126 | do { |
| 131 | 127 | ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg, |
| @@ -147,20 +143,7 @@ brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, · 15 unmodified lines | ||
| 147 | 143 | int ret = 0, retries = 0; |
| 148 | 144 | u32 id, flags; |
| 149 | 145 | |
| 150 | − brcmf_dbg(TRACE, "Enter\n"); | |
| 151 | − brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len); | |
| 152 | − | |
| 153 | − /* Respond "bcmerror" and "bcmerrorstr" with local cache */ | |
| 154 | − if (cmd == BRCMF_C_GET_VAR && buf) { | |
| 155 | − if (!strcmp((char *)buf, "bcmerrorstr")) { | |
| 156 | − strncpy((char *)buf, "bcm_error", | |
| 157 | − BCME_STRLEN); | |
| 158 | − goto done; | |
| 159 | − } else if (!strcmp((char *)buf, "bcmerror")) { | |
| 160 | − *(int *)buf = drvr->dongle_error; | |
| 161 | − goto done; | |
| 162 | − } | |
| 163 | − } | |
| 146 | + brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); | |
| 164 | 147 | |
| 165 | 148 | memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); |
| 166 | 149 | |
| @@ -210,11 +193,8 @@ retry: · 43 unmodified lines | ||
| 210 | 193 | } |
| 211 | 194 | |
| 212 | 195 | /* Check the ERROR flag */ |
| 213 | − if (flags & CDC_DCMD_ERROR) { | |
| 196 | + if (flags & CDC_DCMD_ERROR) | |
| 214 | 197 | ret = le32_to_cpu(msg->status); |
| 215 | − /* Cache error from dongle */ | |
| 216 | − drvr->dongle_error = ret; | |
| 217 | − } | |
| 218 | 198 | |
| 219 | 199 | done: |
| 220 | 200 | return ret; |
| @@ -228,8 +208,7 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, · 7 unmodified lines | ||
| 228 | 208 | int ret = 0; |
| 229 | 209 | u32 flags, id; |
| 230 | 210 | |
| 231 | − brcmf_dbg(TRACE, "Enter\n"); | |
| 232 | − brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len); | |
| 211 | + brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); | |
| 233 | 212 | |
| 234 | 213 | memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); |
| 235 | 214 | |
| @@ -262,11 +241,8 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, · 26 unmodified lines | ||
| 262 | 241 | } |
| 263 | 242 | |
| 264 | 243 | /* Check the ERROR flag */ |
| 265 | − if (flags & CDC_DCMD_ERROR) { | |
| 244 | + if (flags & CDC_DCMD_ERROR) | |
| 266 | 245 | ret = le32_to_cpu(msg->status); |
| 267 | − /* Cache error from dongle */ | |
| 268 | − drvr->dongle_error = ret; | |
| 269 | − } | |
| 270 | 246 | |
| 271 | 247 | done: |
| 272 | 248 | return ret; |
| @@ -287,7 +263,7 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, · 14 unmodified lines | ||
| 287 | 263 | { |
| 288 | 264 | struct brcmf_proto_bdc_header *h; |
| 289 | 265 | |
| 290 | − brcmf_dbg(TRACE, "Enter\n"); | |
| 266 | + brcmf_dbg(CDC, "Enter\n"); | |
| 291 | 267 | |
| 292 | 268 | /* Push BDC header used to convey priority for buses that don't */ |
| 293 | 269 | |
| @@ -305,14 +281,12 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, · 11 unmodified lines | ||
| 305 | 281 | BDC_SET_IF_IDX(h, ifidx); |
| 306 | 282 | } |
| 307 | 283 | |
| 308 | −int brcmf_proto_hdrpull(struct device *dev, int *ifidx, | |
| 284 | +int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, | |
| 309 | 285 | struct sk_buff *pktbuf) |
| 310 | 286 | { |
| 311 | 287 | struct brcmf_proto_bdc_header *h; |
| 312 | − struct brcmf_bus *bus_if = dev_get_drvdata(dev); | |
| 313 | − struct brcmf_pub *drvr = bus_if->drvr; | |
| 314 | 288 | |
| 315 | − brcmf_dbg(TRACE, "Enter\n"); | |
| 289 | + brcmf_dbg(CDC, "Enter\n"); | |
| 316 | 290 | |
| 317 | 291 | /* Pop BDC header used to convey priority for buses that don't */ |
| 318 | 292 | |
| @@ -338,7 +312,7 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx, · 19 unmodified lines | ||
| 338 | 312 | } |
| 339 | 313 | |
| 340 | 314 | if (h->flags & BDC_FLAG_SUM_GOOD) { |
| 341 | − brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n", | |
| 315 | + brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n", | |
| 342 | 316 | brcmf_ifname(drvr, *ifidx), h->flags); |
| 343 | 317 | pkt_set_sum_good(pktbuf, true); |
| 344 | 318 | } |
| @@ -348,6 +322,8 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx, · 3 unmodified lines | ||
| 348 | 322 | skb_pull(pktbuf, BDC_HEADER_LEN); |
| 349 | 323 | skb_pull(pktbuf, h->data_offset << 2); |
| 350 | 324 | |
| 325 | + if (pktbuf->len == 0) | |
| 326 | + return -ENODATA; | |
| 351 | 327 | return 0; |
| 352 | 328 | } |
| 353 | 329 | |
| @@ -14,8 +14,6 @@ · 13 unmodified lines | ||
| 14 | 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 15 | 15 | */ |
| 16 | 16 | |
| 17 | −#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 18 | − | |
| 19 | 17 | #include <linux/kernel.h> |
| 20 | 18 | #include <linux/string.h> |
| 21 | 19 | #include <linux/netdevice.h> |
| @@ -18,21 +18,26 @@ · 17 unmodified lines | ||
| 18 | 18 | #define _BRCMF_DBG_H_ |
| 19 | 19 | |
| 20 | 20 | /* message levels */ |
| 21 | −#define BRCMF_TRACE_VAL 0x0002 | |
| 22 | −#define BRCMF_INFO_VAL 0x0004 | |
| 23 | −#define BRCMF_DATA_VAL 0x0008 | |
| 24 | −#define BRCMF_CTL_VAL 0x0010 | |
| 25 | −#define BRCMF_TIMER_VAL 0x0020 | |
| 26 | −#define BRCMF_HDRS_VAL 0x0040 | |
| 27 | −#define BRCMF_BYTES_VAL 0x0080 | |
| 28 | −#define BRCMF_INTR_VAL 0x0100 | |
| 29 | −#define BRCMF_GLOM_VAL 0x0200 | |
| 30 | −#define BRCMF_EVENT_VAL 0x0400 | |
| 31 | −#define BRCMF_BTA_VAL 0x0800 | |
| 32 | −#define BRCMF_FIL_VAL 0x1000 | |
| 33 | −#define BRCMF_USB_VAL 0x2000 | |
| 34 | −#define BRCMF_SCAN_VAL 0x4000 | |
| 35 | −#define BRCMF_CONN_VAL 0x8000 | |
| 21 | +#define BRCMF_TRACE_VAL 0x00000002 | |
| 22 | +#define BRCMF_INFO_VAL 0x00000004 | |
| 23 | +#define BRCMF_DATA_VAL 0x00000008 | |
| 24 | +#define BRCMF_CTL_VAL 0x00000010 | |
| 25 | +#define BRCMF_TIMER_VAL 0x00000020 | |
| 26 | +#define BRCMF_HDRS_VAL 0x00000040 | |
| 27 | +#define BRCMF_BYTES_VAL 0x00000080 | |
| 28 | +#define BRCMF_INTR_VAL 0x00000100 | |
| 29 | +#define BRCMF_GLOM_VAL 0x00000200 | |
| 30 | +#define BRCMF_EVENT_VAL 0x00000400 | |
| 31 | +#define BRCMF_BTA_VAL 0x00000800 | |
| 32 | +#define BRCMF_FIL_VAL 0x00001000 | |
| 33 | +#define BRCMF_USB_VAL 0x00002000 | |
| 34 | +#define BRCMF_SCAN_VAL 0x00004000 | |
| 35 | +#define BRCMF_CONN_VAL 0x00008000 | |
| 36 | +#define BRCMF_CDC_VAL 0x00010000 | |
| 37 | + | |
| 38 | +/* set default print format */ | |
| 39 | +#undef pr_fmt | |
| 40 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 36 | 41 | |
| 37 | 42 | /* Macro for error messages. net_ratelimit() is used when driver |
| 38 | 43 | * debugging is not selected. When debugging the driver error |
| @@ -14,8 +14,6 @@ · 13 unmodified lines | ||
| 14 | 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 15 | 15 | */ |
| 16 | 16 | |
| 17 | −#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 18 | − | |
| 19 | 17 | #include <linux/kernel.h> |
| 20 | 18 | #include <linux/etherdevice.h> |
| 21 | 19 | #include <linux/module.h> |
| @@ -162,28 +160,31 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev) · 140 unmodified lines | ||
| 162 | 160 | schedule_work(&ifp->multicast_work); |
| 163 | 161 | } |
| 164 | 162 | |
| 165 | −static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |
| 163 | +static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | |
| 164 | + struct net_device *ndev) | |
| 166 | 165 | { |
| 167 | 166 | int ret; |
| 168 | 167 | struct brcmf_if *ifp = netdev_priv(ndev); |
| 169 | 168 | struct brcmf_pub *drvr = ifp->drvr; |
| 169 | + struct ethhdr *eh; | |
| 170 | 170 | |
| 171 | 171 | brcmf_dbg(TRACE, "Enter\n"); |
| 172 | 172 | |
| 173 | − /* Reject if down */ | |
| 174 | − if (!drvr->bus_if->drvr_up || | |
| 175 | − (drvr->bus_if->state != BRCMF_BUS_DATA)) { | |
| 176 | − brcmf_err("xmit rejected drvup=%d state=%d\n", | |
| 177 | − drvr->bus_if->drvr_up, | |
| 178 | − drvr->bus_if->state); | |
| 173 | + /* Can the device send data? */ | |
| 174 | + if (drvr->bus_if->state != BRCMF_BUS_DATA) { | |
| 175 | + brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state); | |
| 179 | 176 | netif_stop_queue(ndev); |
| 180 | − return -ENODEV; | |
| 177 | + dev_kfree_skb(skb); | |
| 178 | + ret = -ENODEV; | |
| 179 | + goto done; | |
| 181 | 180 | } |
| 182 | 181 | |
| 183 | 182 | if (!drvr->iflist[ifp->idx]) { |
| 184 | 183 | brcmf_err("bad ifidx %d\n", ifp->idx); |
| 185 | 184 | netif_stop_queue(ndev); |
| 186 | − return -ENODEV; | |
| 185 | + dev_kfree_skb(skb); | |
| 186 | + ret = -ENODEV; | |
| 187 | + goto done; | |
| 187 | 188 | } |
| 188 | 189 | |
| 189 | 190 | /* Make sure there's enough room for any header */ |
| @@ -204,17 +205,20 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) · 14 unmodified lines | ||
| 204 | 205 | } |
| 205 | 206 | } |
| 206 | 207 | |
| 207 | − /* Update multicast statistic */ | |
| 208 | − if (skb->len >= ETH_ALEN) { | |
| 209 | − u8 *pktdata = (u8 *)(skb->data); | |
| 210 | − struct ethhdr *eh = (struct ethhdr *)pktdata; | |
| 211 | − | |
| 212 | − if (is_multicast_ether_addr(eh->h_dest)) | |
| 213 | − drvr->tx_multicast++; | |
| 214 | − if (ntohs(eh->h_proto) == ETH_P_PAE) | |
| 215 | − atomic_inc(&drvr->pend_8021x_cnt); | |
| 208 | + /* validate length for ether packet */ | |
| 209 | + if (skb->len < sizeof(*eh)) { | |
| 210 | + ret = -EINVAL; | |
| 211 | + dev_kfree_skb(skb); | |
| 212 | + goto done; | |
| 216 | 213 | } |
| 217 | 214 | |
| 215 | + /* handle ethernet header */ | |
| 216 | + eh = (struct ethhdr *)(skb->data); | |
| 217 | + if (is_multicast_ether_addr(eh->h_dest)) | |
| 218 | + drvr->tx_multicast++; | |
| 219 | + if (ntohs(eh->h_proto) == ETH_P_PAE) | |
| 220 | + atomic_inc(&drvr->pend_8021x_cnt); | |
| 221 | + | |
| 218 | 222 | /* If the protocol uses a data header, apply it */ |
| 219 | 223 | brcmf_proto_hdrpush(drvr, ifp->idx, skb); |
| 220 | 224 | |
| @@ -228,7 +232,7 @@ done: · 7 unmodified lines | ||
| 228 | 232 | drvr->bus_if->dstats.tx_packets++; |
| 229 | 233 | |
| 230 | 234 | /* Return ok: we always eat the packet */ |
| 231 | − return 0; | |
| 235 | + return NETDEV_TX_OK; | |
| 232 | 236 | } |
| 233 | 237 | |
| 234 | 238 | void brcmf_txflowblock(struct device *dev, bool state) |
| @@ -250,8 +254,7 @@ void brcmf_txflowblock(struct device *dev, bool state) · 15 unmodified lines | ||
| 250 | 254 | } |
| 251 | 255 | } |
| 252 | 256 | |
| 253 | −void brcmf_rx_frame(struct device *dev, u8 ifidx, | |
| 254 | − struct sk_buff_head *skb_list) | |
| 257 | +void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) | |
| 255 | 258 | { |
| 256 | 259 | unsigned char *eth; |
| 257 | 260 | uint len; |
| @@ -259,12 +262,24 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx, · 1 unmodified line | ||
| 259 | 262 | struct brcmf_if *ifp; |
| 260 | 263 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
| 261 | 264 | struct brcmf_pub *drvr = bus_if->drvr; |
| 265 | + u8 ifidx; | |
| 266 | + int ret; | |
| 262 | 267 | |
| 263 | 268 | brcmf_dbg(TRACE, "Enter\n"); |
| 264 | 269 | |
| 265 | 270 | skb_queue_walk_safe(skb_list, skb, pnext) { |
| 266 | 271 | skb_unlink(skb, skb_list); |
| 267 | 272 | |
| 273 | + /* process and remove protocol-specific header | |
| 274 | + */ | |
| 275 | + ret = brcmf_proto_hdrpull(drvr, &ifidx, skb); | |
| 276 | + if (ret < 0) { | |
| 277 | + if (ret != -ENODATA) | |
| 278 | + bus_if->dstats.rx_errors++; | |
| 279 | + brcmu_pkt_buf_free_skb(skb); | |
| 280 | + continue; | |
| 281 | + } | |
| 282 | + | |
| 268 | 283 | /* Get the protocol, maintain skb around eth_type_trans() |
| 269 | 284 | * The main reason for this hack is for the limitation of |
| 270 | 285 | * Linux 2.4 where 'eth_type_trans' uses the |
| @@ -328,13 +343,13 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx, · 57 unmodified lines | ||
| 328 | 343 | |
| 329 | 344 | void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) |
| 330 | 345 | { |
| 331 | − uint ifidx; | |
| 346 | + u8 ifidx; | |
| 332 | 347 | struct ethhdr *eh; |
| 333 | 348 | u16 type; |
| 334 | 349 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
| 335 | 350 | struct brcmf_pub *drvr = bus_if->drvr; |
| 336 | 351 | |
| 337 | − brcmf_proto_hdrpull(dev, &ifidx, txp); | |
| 352 | + brcmf_proto_hdrpull(drvr, &ifidx, txp); | |
| 338 | 353 | |
| 339 | 354 | eh = (struct ethhdr *)(txp->data); |
| 340 | 355 | type = ntohs(eh->h_proto); |
| @@ -450,7 +465,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) · 109 unmodified lines | ||
| 450 | 465 | sprintf(info.version, "%lu", drvr->drv_version); |
| 451 | 466 | if (copy_to_user(uaddr, &info, sizeof(info))) |
| 452 | 467 | return -EFAULT; |
| 453 | − brcmf_dbg(CTL, "given %*s, returning %s\n", | |
| 468 | + brcmf_dbg(TRACE, "given %*s, returning %s\n", | |
| 454 | 469 | (int)sizeof(drvname), drvname, info.driver); |
| 455 | 470 | break; |
| 456 | 471 | |
| @@ -570,14 +585,9 @@ static int brcmf_netdev_open(struct net_device *ndev) · 113 unmodified lines | ||
| 570 | 585 | /* Get current TOE mode from dongle */ |
| 571 | 586 | if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 |
| 572 | 587 | && (toe_ol & TOE_TX_CSUM_OL) != 0) |
| 573 | − drvr->iflist[ifp->idx]->ndev->features |= | |
| 574 | − NETIF_F_IP_CSUM; | |
| 588 | + ndev->features |= NETIF_F_IP_CSUM; | |
| 575 | 589 | else |
| 576 | − drvr->iflist[ifp->idx]->ndev->features &= | |
| 577 | − ~NETIF_F_IP_CSUM; | |
| 578 | − | |
| 579 | − /* make sure RF is ready for work */ | |
| 580 | − brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); | |
| 590 | + ndev->features &= ~NETIF_F_IP_CSUM; | |
| 581 | 591 | |
| 582 | 592 | /* Allow transmit calls */ |
| 583 | 593 | netif_start_queue(ndev); |
| @@ -845,6 +855,17 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr) · 261 unmodified lines | ||
| 845 | 855 | } |
| 846 | 856 | } |
| 847 | 857 | |
| 858 | +void brcmf_dev_reset(struct device *dev) | |
| 859 | +{ | |
| 860 | + struct brcmf_bus *bus_if = dev_get_drvdata(dev); | |
| 861 | + struct brcmf_pub *drvr = bus_if->drvr; | |
| 862 | + | |
| 863 | + if (drvr == NULL) | |
| 864 | + return; | |
| 865 | + | |
| 866 | + brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); | |
| 867 | +} | |
| 868 | + | |
| 848 | 869 | void brcmf_detach(struct device *dev) |
| 849 | 870 | { |
| 850 | 871 | int i; |
| @@ -866,9 +887,8 @@ void brcmf_detach(struct device *dev) · 15 unmodified lines | ||
| 866 | 887 | |
| 867 | 888 | brcmf_bus_detach(drvr); |
| 868 | 889 | |
| 869 | − if (drvr->prot) { | |
| 890 | + if (drvr->prot) | |
| 870 | 891 | brcmf_proto_detach(drvr); |
| 871 | − } | |
| 872 | 892 | |
| 873 | 893 | brcmf_debugfs_detach(drvr); |
| 874 | 894 | bus_if->drvr = NULL; |
| @@ -14,8 +14,6 @@ · 13 unmodified lines | ||
| 14 | 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 15 | 15 | */ |
| 16 | 16 | |
| 17 | −#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 18 | − | |
| 19 | 17 | #include <linux/types.h> |
| 20 | 18 | #include <linux/kernel.h> |
| 21 | 19 | #include <linux/kthread.h> |
| @@ -1169,7 +1167,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) · 1147 unmodified lines | ||
| 1169 | 1167 | int errcode; |
| 1170 | 1168 | u8 doff, sfdoff; |
| 1171 | 1169 | |
| 1172 | − int ifidx = 0; | |
| 1173 | 1170 | bool usechain = bus->use_rxchain; |
| 1174 | 1171 | |
| 1175 | 1172 | struct brcmf_sdio_read rd_new; |
| @@ -1388,13 +1385,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) · 212 unmodified lines | ||
| 1388 | 1385 | skb_unlink(pfirst, &bus->glom); |
| 1389 | 1386 | brcmu_pkt_buf_free_skb(pfirst); |
| 1390 | 1387 | continue; |
| 1391 | − } else if (brcmf_proto_hdrpull(bus->sdiodev->dev, | |
| 1392 | − &ifidx, pfirst) != 0) { | |
| 1393 | − brcmf_err("rx protocol error\n"); | |
| 1394 | − bus->sdiodev->bus_if->dstats.rx_errors++; | |
| 1395 | − skb_unlink(pfirst, &bus->glom); | |
| 1396 | − brcmu_pkt_buf_free_skb(pfirst); | |
| 1397 | − continue; | |
| 1398 | 1388 | } |
| 1399 | 1389 | |
| 1400 | 1390 | brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), |
| @@ -1407,7 +1397,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) · 6 unmodified lines | ||
| 1407 | 1397 | } |
| 1408 | 1398 | /* sent any remaining packets up */ |
| 1409 | 1399 | if (bus->glom.qlen) |
| 1410 | − brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom); | |
| 1400 | + brcmf_rx_frames(bus->sdiodev->dev, &bus->glom); | |
| 1411 | 1401 | |
| 1412 | 1402 | bus->sdcnt.rxglomframes++; |
| 1413 | 1403 | bus->sdcnt.rxglompkts += bus->glom.qlen; |
| @@ -1558,10 +1548,10 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen) · 144 unmodified lines | ||
| 1558 | 1548 | static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) |
| 1559 | 1549 | { |
| 1560 | 1550 | struct sk_buff *pkt; /* Packet for event or data frames */ |
| 1551 | + struct sk_buff_head pktlist; /* needed for bus interface */ | |
| 1561 | 1552 | u16 pad; /* Number of pad bytes to read */ |
| 1562 | 1553 | uint rxleft = 0; /* Remaining number of frames allowed */ |
| 1563 | 1554 | int sdret; /* Return code from calls */ |
| 1564 | − int ifidx = 0; | |
| 1565 | 1555 | uint rxcount = 0; /* Total frames read */ |
| 1566 | 1556 | struct brcmf_sdio_read *rd = &bus->cur_read, rd_new; |
| 1567 | 1557 | u8 head_read = 0; |
| @@ -1760,15 +1750,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) · 192 unmodified lines | ||
| 1760 | 1750 | if (pkt->len == 0) { |
| 1761 | 1751 | brcmu_pkt_buf_free_skb(pkt); |
| 1762 | 1752 | continue; |
| 1763 | − } else if (brcmf_proto_hdrpull(bus->sdiodev->dev, &ifidx, | |
| 1764 | − pkt) != 0) { | |
| 1765 | − brcmf_err("rx protocol error\n"); | |
| 1766 | − brcmu_pkt_buf_free_skb(pkt); | |
| 1767 | − bus->sdiodev->bus_if->dstats.rx_errors++; | |
| 1768 | − continue; | |
| 1769 | 1753 | } |
| 1770 | 1754 | |
| 1771 | − brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt); | |
| 1755 | + skb_queue_head_init(&pktlist); | |
| 1756 | + skb_queue_tail(&pktlist, pkt); | |
| 1757 | + brcmf_rx_frames(bus->sdiodev->dev, &pktlist); | |
| 1772 | 1758 | } |
| 1773 | 1759 | |
| 1774 | 1760 | rxcount = maxframes - rxleft; |
| @@ -15,8 +15,6 @@ · 14 unmodified lines | ||
| 15 | 15 | */ |
| 16 | 16 | /* ***** SDIO interface chip backplane handle functions ***** */ |
| 17 | 17 | |
| 18 | −#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 19 | − | |
| 20 | 18 | #include <linux/types.h> |
| 21 | 19 | #include <linux/netdevice.h> |
| 22 | 20 | #include <linux/mmc/card.h> |
| @@ -443,14 +443,15 @@ static void brcmf_usb_rx_complete(struct urb *urb) · 442 unmodified lines | ||
| 443 | 443 | struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context; |
| 444 | 444 | struct brcmf_usbdev_info *devinfo = req->devinfo; |
| 445 | 445 | struct sk_buff *skb; |
| 446 | − int ifidx = 0; | |
| 446 | + struct sk_buff_head skbq; | |
| 447 | 447 | |
| 448 | 448 | brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status); |
| 449 | 449 | brcmf_usb_del_fromq(devinfo, req); |
| 450 | 450 | skb = req->skb; |
| 451 | 451 | req->skb = NULL; |
| 452 | 452 | |
| 453 | − if (urb->status == 0) { | |
| 453 | + /* zero lenght packets indicate usb "failure". Do not refill */ | |
| 454 | + if (urb->status == 0 && urb->actual_length) { | |
| 454 | 455 | devinfo->bus_pub.bus->dstats.rx_packets++; |
| 455 | 456 | } else { |
| 456 | 457 | devinfo->bus_pub.bus->dstats.rx_errors++; |
| @@ -460,13 +461,10 @@ static void brcmf_usb_rx_complete(struct urb *urb) · 3 unmodified lines | ||
| 460 | 461 | } |
| 461 | 462 | |
| 462 | 463 | if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { |
| 464 | + skb_queue_head_init(&skbq); | |
| 465 | + skb_queue_tail(&skbq, skb); | |
| 463 | 466 | skb_put(skb, urb->actual_length); |
| 464 | − if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { | |
| 465 | − brcmf_err("rx protocol error\n"); | |
| 466 | − brcmu_pkt_buf_free_skb(skb); | |
| 467 | − devinfo->bus_pub.bus->dstats.rx_errors++; | |
| 468 | − } else | |
| 469 | − brcmf_rx_packet(devinfo->dev, ifidx, skb); | |
| 467 | + brcmf_rx_frames(devinfo->dev, &skbq); | |
| 470 | 468 | brcmf_usb_rx_refill(devinfo, req); |
| 471 | 469 | } else { |
| 472 | 470 | brcmu_pkt_buf_free_skb(skb); |
| @@ -1520,10 +1518,23 @@ static void brcmf_release_fw(struct list_head *q) · 1047 unmodified lines | ||
| 1520 | 1518 | } |
| 1521 | 1519 | } |
| 1522 | 1520 | |
| 1521 | +static int brcmf_usb_reset_device(struct device *dev, void *notused) | |
| 1522 | +{ | |
| 1523 | + /* device past is the usb interface so we | |
| 1524 | + * need to use parent here. | |
| 1525 | + */ | |
| 1526 | + brcmf_dev_reset(dev->parent); | |
| 1527 | + return 0; | |
| 1528 | +} | |
| 1523 | 1529 | |
| 1524 | 1530 | void brcmf_usb_exit(void) |
| 1525 | 1531 | { |
| 1532 | + struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver; | |
| 1533 | + int ret; | |
| 1534 | + | |
| 1526 | 1535 | brcmf_dbg(USB, "Enter\n"); |
| 1536 | + ret = driver_for_each_device(drv, NULL, NULL, | |
| 1537 | + brcmf_usb_reset_device); | |
| 1527 | 1538 | usb_deregister(&brcmf_usbdrvr); |
| 1528 | 1539 | brcmf_release_fw(&fw_image_list); |
| 1529 | 1540 | } |
| @@ -16,8 +16,6 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | /* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */ |
| 18 | 18 | |
| 19 | −#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 20 | − | |
| 21 | 19 | #include <linux/kernel.h> |
| 22 | 20 | #include <linux/etherdevice.h> |
| 23 | 21 | #include <net/cfg80211.h> |
| @@ -2011,67 +2009,6 @@ done: · 1987 unmodified lines | ||
| 2011 | 2009 | return err; |
| 2012 | 2010 | } |
| 2013 | 2011 | |
| 2014 | −static s32 | |
| 2015 | −brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev, | |
| 2016 | − const u8 *addr, | |
| 2017 | − const struct cfg80211_bitrate_mask *mask) | |
| 2018 | −{ | |
| 2019 | − struct brcmf_if *ifp = netdev_priv(ndev); | |
| 2020 | − struct brcm_rateset_le rateset_le; | |
| 2021 | − s32 rate; | |
| 2022 | − s32 val; | |
| 2023 | − s32 err_bg; | |
| 2024 | − s32 err_a; | |
| 2025 | − u32 legacy; | |
| 2026 | − s32 err = 0; | |
| 2027 | − | |
| 2028 | − brcmf_dbg(TRACE, "Enter\n"); | |
| 2029 | − if (!check_vif_up(ifp->vif)) | |
| 2030 | − return -EIO; | |
| 2031 | − | |
| 2032 | − /* addr param is always NULL. ignore it */ | |
| 2033 | − /* Get current rateset */ | |
| 2034 | − err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CURR_RATESET, | |
| 2035 | − &rateset_le, sizeof(rateset_le)); | |
| 2036 | − if (err) { | |
| 2037 | − brcmf_err("could not get current rateset (%d)\n", err); | |
| 2038 | − goto done; | |
| 2039 | − } | |
| 2040 | − | |
| 2041 | − legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF); | |
| 2042 | − if (!legacy) | |
| 2043 | − legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy & | |
| 2044 | − 0xFFFF); | |
| 2045 | − | |
| 2046 | − val = wl_g_rates[legacy - 1].bitrate * 100000; | |
| 2047 | − | |
| 2048 | − if (val < le32_to_cpu(rateset_le.count)) | |
| 2049 | − /* Select rate by rateset index */ | |
| 2050 | − rate = rateset_le.rates[val] & 0x7f; | |
| 2051 | − else | |
| 2052 | − /* Specified rate in bps */ | |
| 2053 | − rate = val / 500000; | |
| 2054 | − | |
| 2055 | − brcmf_dbg(CONN, "rate %d mbps\n", rate / 2); | |
| 2056 | − | |
| 2057 | − /* | |
| 2058 | − * | |
| 2059 | − * Set rate override, | |
| 2060 | − * Since the is a/b/g-blind, both a/bg_rate are enforced. | |
| 2061 | − */ | |
| 2062 | − err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate); | |
| 2063 | − err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate); | |
| 2064 | − if (err_bg && err_a) { | |
| 2065 | − brcmf_err("could not set fixed rate (%d) (%d)\n", err_bg, | |
| 2066 | − err_a); | |
| 2067 | − err = err_bg | err_a; | |
| 2068 | − } | |
| 2069 | − | |
| 2070 | −done: | |
| 2071 | − brcmf_dbg(TRACE, "Exit\n"); | |
| 2072 | − return err; | |
| 2073 | −} | |
| 2074 | − | |
| 2075 | 2012 | static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, |
| 2076 | 2013 | struct brcmf_bss_info_le *bi) |
| 2077 | 2014 | { |
| @@ -3091,10 +3028,11 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, · 1013 unmodified lines | ||
| 3091 | 3028 | |
| 3092 | 3029 | len = wpa_ie->len + TLV_HDR_LEN; |
| 3093 | 3030 | data = (u8 *)wpa_ie; |
| 3094 | − offset = 0; | |
| 3031 | + offset = TLV_HDR_LEN; | |
| 3095 | 3032 | if (!is_rsn_ie) |
| 3096 | 3033 | offset += VS_IE_FIXED_HDR_LEN; |
| 3097 | − offset += WPA_IE_VERSION_LEN; | |
| 3034 | + else | |
| 3035 | + offset += WPA_IE_VERSION_LEN; | |
| 3098 | 3036 | |
| 3099 | 3037 | /* check for multicast cipher suite */ |
| 3100 | 3038 | if (offset + WPA_IE_MIN_OUI_LEN > len) { |
| @@ -3703,7 +3641,6 @@ static struct cfg80211_ops wl_cfg80211_ops = { · 602 unmodified lines | ||
| 3703 | 3641 | .set_default_key = brcmf_cfg80211_config_default_key, |
| 3704 | 3642 | .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key, |
| 3705 | 3643 | .set_power_mgmt = brcmf_cfg80211_set_power_mgmt, |
| 3706 | − .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask, | |
| 3707 | 3644 | .connect = brcmf_cfg80211_connect, |
| 3708 | 3645 | .disconnect = brcmf_cfg80211_disconnect, |
| 3709 | 3646 | .suspend = brcmf_cfg80211_suspend, |
| @@ -4329,9 +4266,8 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) · 619 unmodified lines | ||
| 4329 | 4266 | } |
| 4330 | 4267 | |
| 4331 | 4268 | static s32 |
| 4332 | −brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) | |
| 4269 | +brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout) | |
| 4333 | 4270 | { |
| 4334 | − struct brcmf_if *ifp = netdev_priv(ndev); | |
| 4335 | 4271 | s32 err = 0; |
| 4336 | 4272 | __le32 roamtrigger[2]; |
| 4337 | 4273 | __le32 roam_delta[2]; |
| @@ -4382,10 +4318,9 @@ dongle_rom_out: · 44 unmodified lines | ||
| 4382 | 4318 | } |
| 4383 | 4319 | |
| 4384 | 4320 | static s32 |
| 4385 | −brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, | |
| 4321 | +brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time, | |
| 4386 | 4322 | s32 scan_unassoc_time, s32 scan_passive_time) |
| 4387 | 4323 | { |
| 4388 | − struct brcmf_if *ifp = netdev_priv(ndev); | |
| 4389 | 4324 | s32 err = 0; |
| 4390 | 4325 | |
| 4391 | 4326 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME, |
| @@ -4455,6 +4390,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) · 63 unmodified lines | ||
| 4455 | 4390 | { |
| 4456 | 4391 | struct net_device *ndev; |
| 4457 | 4392 | struct wireless_dev *wdev; |
| 4393 | + struct brcmf_if *ifp; | |
| 4458 | 4394 | s32 power_mode; |
| 4459 | 4395 | s32 err = 0; |
| 4460 | 4396 | |
| @@ -4463,35 +4399,34 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) · 2 unmodified lines | ||
| 4463 | 4399 | |
| 4464 | 4400 | ndev = cfg_to_ndev(cfg); |
| 4465 | 4401 | wdev = ndev->ieee80211_ptr; |
| 4402 | + ifp = netdev_priv(ndev); | |
| 4466 | 4403 | |
| 4467 | − brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME, | |
| 4468 | − WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); | |
| 4404 | + /* make sure RF is ready for work */ | |
| 4405 | + brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); | |
| 4406 | + | |
| 4407 | + brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME, | |
| 4408 | + WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); | |
| 4469 | 4409 | |
| 4470 | 4410 | power_mode = cfg->pwr_save ? PM_FAST : PM_OFF; |
| 4471 | − err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM, | |
| 4472 | − power_mode); | |
| 4411 | + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode); | |
| 4473 | 4412 | if (err) |
| 4474 | 4413 | goto default_conf_out; |
| 4475 | 4414 | brcmf_dbg(INFO, "power save set to %s\n", |
| 4476 | 4415 | (power_mode ? "enabled" : "disabled")); |
| 4477 | 4416 | |
| 4478 | − err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1), | |
| 4479 | − WL_BEACON_TIMEOUT); | |
| 4417 | + err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT); | |
| 4480 | 4418 | if (err) |
| 4481 | 4419 | goto default_conf_out; |
| 4482 | 4420 | err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype, |
| 4483 | 4421 | NULL, NULL); |
| 4484 | − if (err && err != -EINPROGRESS) | |
| 4422 | + if (err) | |
| 4485 | 4423 | goto default_conf_out; |
| 4486 | 4424 | err = brcmf_dongle_probecap(cfg); |
| 4487 | 4425 | if (err) |
| 4488 | 4426 | goto default_conf_out; |
| 4489 | 4427 | |
| 4490 | − /* -EINPROGRESS: Call commit handler */ | |
| 4491 | − | |
| 4492 | −default_conf_out: | |
| 4493 | − | |
| 4494 | 4428 | cfg->dongle_up = true; |
| 4429 | +default_conf_out: | |
| 4495 | 4430 | |
| 4496 | 4431 | return err; |
| 4497 | 4432 | |
| @@ -4500,8 +4435,6 @@ default_conf_out: · 2 unmodified lines | ||
| 4500 | 4435 | static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp) |
| 4501 | 4436 | { |
| 4502 | 4437 | set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state); |
| 4503 | − if (ifp->idx) | |
| 4504 | − return 0; | |
| 4505 | 4438 | |
| 4506 | 4439 | return brcmf_config_dongle(ifp->drvr->config); |
| 4507 | 4440 | } |
| @@ -961,7 +961,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, · 960 unmodified lines | ||
| 961 | 961 | /* if acked then clear bit and free packet */ |
| 962 | 962 | if ((bindex < AMPDU_TX_BA_MAX_WSIZE) |
| 963 | 963 | && isset(bitmap, bindex)) { |
| 964 | − ini->tx_in_transit--; | |
| 965 | 964 | ini->txretry[index] = 0; |
| 966 | 965 | |
| 967 | 966 | /* |
| @@ -990,7 +989,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, · 22 unmodified lines | ||
| 990 | 989 | if (retry && (ini->txretry[index] < (int)retry_limit)) { |
| 991 | 990 | int ret; |
| 992 | 991 | ini->txretry[index]++; |
| 993 | − ini->tx_in_transit--; | |
| 994 | 992 | ret = brcms_c_txfifo(wlc, queue, p); |
| 995 | 993 | /* |
| 996 | 994 | * We shouldn't be out of space in the DMA |
| @@ -1000,7 +998,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, · 3 unmodified lines | ||
| 1000 | 998 | WARN_ONCE(ret, "queue %d out of txds\n", queue); |
| 1001 | 999 | } else { |
| 1002 | 1000 | /* Retry timeout */ |
| 1003 | − ini->tx_in_transit--; | |
| 1004 | 1001 | ieee80211_tx_info_clear_status(tx_info); |
| 1005 | 1002 | tx_info->status.ampdu_ack_len = 0; |
| 1006 | 1003 | tx_info->status.ampdu_len = 1; |
| @@ -1009,8 +1006,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, · 2 unmodified lines | ||
| 1009 | 1006 | skb_pull(p, D11_PHY_HDR_LEN); |
| 1010 | 1007 | skb_pull(p, D11_TXH_LEN); |
| 1011 | 1008 | brcms_dbg_ht(wlc->hw->d11core, |
| 1012 | − "BA Timeout, seq %d, in_transit %d\n", | |
| 1013 | − seq, ini->tx_in_transit); | |
| 1009 | + "BA Timeout, seq %d\n", | |
| 1010 | + seq); | |
| 1014 | 1011 | ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, |
| 1015 | 1012 | p); |
| 1016 | 1013 | } |
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | /* |
| 2 | 2 | * Copyright (c) 2012 Broadcom Corporation |
| 3 | + * Copyright (c) 2012 Canonical Ltd. | |
| 3 | 4 | * |
| 4 | 5 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | 6 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -362,8 +362,11 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) · 361 unmodified lines | ||
| 362 | 362 | return -EOPNOTSUPP; |
| 363 | 363 | } |
| 364 | 364 | |
| 365 | + spin_lock_bh(&wl->lock); | |
| 366 | + memcpy(wl->pub->cur_etheraddr, vif->addr, sizeof(vif->addr)); | |
| 365 | 367 | wl->mute_tx = false; |
| 366 | 368 | brcms_c_mute(wl->wlc, false); |
| 369 | + spin_unlock_bh(&wl->lock); | |
| 367 | 370 | |
| 368 | 371 | return 0; |
| 369 | 372 | } |
| @@ -1408,9 +1411,10 @@ void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic) · 1038 unmodified lines | ||
| 1408 | 1411 | #endif |
| 1409 | 1412 | t->ms = ms; |
| 1410 | 1413 | t->periodic = (bool) periodic; |
| 1411 | − t->set = true; | |
| 1412 | − | |
| 1413 | − atomic_inc(&t->wl->callbacks); | |
| 1414 | + if (!t->set) { | |
| 1415 | + t->set = true; | |
| 1416 | + atomic_inc(&t->wl->callbacks); | |
| 1417 | + } | |
| 1414 | 1418 | |
| 1415 | 1419 | ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms)); |
| 1416 | 1420 | } |
| @@ -2473,6 +2473,7 @@ static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw, · 2472 unmodified lines | ||
| 2473 | 2473 | static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx) |
| 2474 | 2474 | { |
| 2475 | 2475 | static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; |
| 2476 | + u8 *ethaddr = wlc_hw->wlc->pub->cur_etheraddr; | |
| 2476 | 2477 | |
| 2477 | 2478 | if (mute_tx) { |
| 2478 | 2479 | /* suspend tx fifos */ |
| @@ -2482,8 +2483,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx) · 3 unmodified lines | ||
| 2482 | 2483 | brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO); |
| 2483 | 2484 | |
| 2484 | 2485 | /* zero the address match register so we do not send ACKs */ |
| 2485 | − brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, | |
| 2486 | − null_ether_addr); | |
| 2486 | + brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, null_ether_addr); | |
| 2487 | 2487 | } else { |
| 2488 | 2488 | /* resume tx fifos */ |
| 2489 | 2489 | brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO); |
| @@ -2492,8 +2492,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx) · 2 unmodified lines | ||
| 2492 | 2492 | brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO); |
| 2493 | 2493 | |
| 2494 | 2494 | /* Restore address */ |
| 2495 | − brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, | |
| 2496 | − wlc_hw->etheraddr); | |
| 2495 | + brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, ethaddr); | |
| 2497 | 2496 | } |
| 2498 | 2497 | |
| 2499 | 2498 | wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0); |
| @@ -7633,7 +7632,7 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) · 5133 unmodified lines | ||
| 7633 | 7632 | |
| 7634 | 7633 | uint n = 0; |
| 7635 | 7634 | uint bound_limit = bound ? RXBND : -1; |
| 7636 | − bool morepending; | |
| 7635 | + bool morepending = false; | |
| 7637 | 7636 | |
| 7638 | 7637 | skb_queue_head_init(&recv_frames); |
| 7639 | 7638 | |
| @@ -1343,13 +1343,13 @@ static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain, · 1342 unmodified lines | ||
| 1343 | 1343 | |
| 1344 | 1344 | wlc_lcnphy_rx_gain_override_enable(pi, true); |
| 1345 | 1345 | wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0); |
| 1346 | − usleep_range(500, 500); | |
| 1346 | + udelay(500); | |
| 1347 | 1347 | write_radio_reg(pi, RADIO_2064_REG112, 0); |
| 1348 | 1348 | if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l)) |
| 1349 | 1349 | return false; |
| 1350 | 1350 | |
| 1351 | 1351 | wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0); |
| 1352 | − usleep_range(500, 500); | |
| 1352 | + udelay(500); | |
| 1353 | 1353 | write_radio_reg(pi, RADIO_2064_REG112, 0); |
| 1354 | 1354 | if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h)) |
| 1355 | 1355 | return false; |
| @@ -36,7 +36,6 @@ · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | /* structure to store per-tid state for the ampdu initiator */ |
| 38 | 38 | struct scb_ampdu_tid_ini { |
| 39 | − u8 tx_in_transit; /* number of pending mpdus in transit in driver */ | |
| 40 | 39 | u8 tid; /* initiator tid for easy lookup */ |
| 41 | 40 | /* tx retry count; indexed by seq modulo */ |
| 42 | 41 | u8 txretry[AMPDU_TX_BA_MAX_WSIZE]; |
| @@ -3273,7 +3273,7 @@ il3945_store_measurement(struct device *d, struct device_attribute *attr, · 3272 unmodified lines | ||
| 3273 | 3273 | |
| 3274 | 3274 | if (count) { |
| 3275 | 3275 | char *p = buffer; |
| 3276 | − strncpy(buffer, buf, min(sizeof(buffer), count)); | |
| 3276 | + strlcpy(buffer, buf, sizeof(buffer)); | |
| 3277 | 3277 | channel = simple_strtoul(p, NULL, 0); |
| 3278 | 3278 | if (channel) |
| 3279 | 3279 | params.channel = channel; |
| @@ -3474,6 +3474,7 @@ struct ieee80211_ops il3945_mac_ops = { · 194 unmodified lines | ||
| 3474 | 3474 | .sta_add = il3945_mac_sta_add, |
| 3475 | 3475 | .sta_remove = il_mac_sta_remove, |
| 3476 | 3476 | .tx_last_beacon = il_mac_tx_last_beacon, |
| 3477 | + .flush = il_mac_flush, | |
| 3477 | 3478 | }; |
| 3478 | 3479 | |
| 3479 | 3480 | static int |
| @@ -3548,7 +3549,8 @@ il3945_setup_mac(struct il_priv *il) · 68 unmodified lines | ||
| 3548 | 3549 | hw->vif_data_size = sizeof(struct il_vif_priv); |
| 3549 | 3550 | |
| 3550 | 3551 | /* Tell mac80211 our characteristics */ |
| 3551 | − hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT; | |
| 3552 | + hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT | | |
| 3553 | + IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; | |
| 3552 | 3554 | |
| 3553 | 3555 | hw->wiphy->interface_modes = |
| 3554 | 3556 | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); |
| @@ -3557,6 +3559,8 @@ il3945_setup_mac(struct il_priv *il) · 2 unmodified lines | ||
| 3557 | 3559 | WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS | |
| 3558 | 3560 | WIPHY_FLAG_IBSS_RSN; |
| 3559 | 3561 | |
| 3562 | + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | |
| 3563 | + | |
| 3560 | 3564 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; |
| 3561 | 3565 | /* we create the 802.11 header and a zero-length SSID element */ |
| 3562 | 3566 | hw->wiphy->max_scan_ie_len = IL3945_MAX_PROBE_REQUEST - 24 - 2; |
| @@ -5712,8 +5712,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) · 5711 unmodified lines | ||
| 5712 | 5712 | hw->flags = |
| 5713 | 5713 | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION | |
| 5714 | 5714 | IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT | |
| 5715 | − IEEE80211_HW_REPORTS_TX_ACK_STATUS; | |
| 5716 | − | |
| 5715 | + IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | | |
| 5716 | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; | |
| 5717 | 5717 | if (il->cfg->sku & IL_SKU_N) |
| 5718 | 5718 | hw->flags |= |
| 5719 | 5719 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | |
| @@ -6308,6 +6308,7 @@ const struct ieee80211_ops il4965_mac_ops = { · 588 unmodified lines | ||
| 6308 | 6308 | .sta_remove = il_mac_sta_remove, |
| 6309 | 6309 | .channel_switch = il4965_mac_channel_switch, |
| 6310 | 6310 | .tx_last_beacon = il_mac_tx_last_beacon, |
| 6311 | + .flush = il_mac_flush, | |
| 6311 | 6312 | }; |
| 6312 | 6313 | |
| 6313 | 6314 | static int |
| @@ -6555,6 +6556,7 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 241 unmodified lines | ||
| 6555 | 6556 | il4965_prepare_card_hw(il); |
| 6556 | 6557 | if (!il->hw_ready) { |
| 6557 | 6558 | IL_WARN("Failed, HW not ready\n"); |
| 6559 | + err = -EIO; | |
| 6558 | 6560 | goto out_iounmap; |
| 6559 | 6561 | } |
| 6560 | 6562 | |
| @@ -3958,17 +3958,21 @@ il_connection_init_rx_config(struct il_priv *il) · 3957 unmodified lines | ||
| 3958 | 3958 | |
| 3959 | 3959 | memset(&il->staging, 0, sizeof(il->staging)); |
| 3960 | 3960 | |
| 3961 | − if (!il->vif) { | |
| 3961 | + switch (il->iw_mode) { | |
| 3962 | + case NL80211_IFTYPE_UNSPECIFIED: | |
| 3962 | 3963 | il->staging.dev_type = RXON_DEV_TYPE_ESS; |
| 3963 | − } else if (il->vif->type == NL80211_IFTYPE_STATION) { | |
| 3964 | + break; | |
| 3965 | + case NL80211_IFTYPE_STATION: | |
| 3964 | 3966 | il->staging.dev_type = RXON_DEV_TYPE_ESS; |
| 3965 | 3967 | il->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; |
| 3966 | − } else if (il->vif->type == NL80211_IFTYPE_ADHOC) { | |
| 3968 | + break; | |
| 3969 | + case NL80211_IFTYPE_ADHOC: | |
| 3967 | 3970 | il->staging.dev_type = RXON_DEV_TYPE_IBSS; |
| 3968 | 3971 | il->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK; |
| 3969 | 3972 | il->staging.filter_flags = |
| 3970 | 3973 | RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK; |
| 3971 | − } else { | |
| 3974 | + break; | |
| 3975 | + default: | |
| 3972 | 3976 | IL_ERR("Unsupported interface type %d\n", il->vif->type); |
| 3973 | 3977 | return; |
| 3974 | 3978 | } |
| @@ -4550,8 +4554,7 @@ out: · 575 unmodified lines | ||
| 4550 | 4554 | EXPORT_SYMBOL(il_mac_add_interface); |
| 4551 | 4555 | |
| 4552 | 4556 | static void |
| 4553 | −il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif, | |
| 4554 | − bool mode_change) | |
| 4557 | +il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif) | |
| 4555 | 4558 | { |
| 4556 | 4559 | lockdep_assert_held(&il->mutex); |
| 4557 | 4560 | |
| @@ -4560,9 +4563,7 @@ il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif, · 2 unmodified lines | ||
| 4560 | 4563 | il_force_scan_end(il); |
| 4561 | 4564 | } |
| 4562 | 4565 | |
| 4563 | − if (!mode_change) | |
| 4564 | − il_set_mode(il); | |
| 4565 | − | |
| 4566 | + il_set_mode(il); | |
| 4566 | 4567 | } |
| 4567 | 4568 | |
| 4568 | 4569 | void |
| @@ -4575,8 +4576,8 @@ il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) · 6 unmodified lines | ||
| 4575 | 4576 | |
| 4576 | 4577 | WARN_ON(il->vif != vif); |
| 4577 | 4578 | il->vif = NULL; |
| 4578 | − | |
| 4579 | − il_teardown_interface(il, vif, false); | |
| 4579 | + il->iw_mode = NL80211_IFTYPE_UNSPECIFIED; | |
| 4580 | + il_teardown_interface(il, vif); | |
| 4580 | 4581 | memset(il->bssid, 0, ETH_ALEN); |
| 4581 | 4582 | |
| 4582 | 4583 | D_MAC80211("leave\n"); |
| @@ -4685,18 +4686,10 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 102 unmodified lines | ||
| 4685 | 4686 | } |
| 4686 | 4687 | |
| 4687 | 4688 | /* success */ |
| 4688 | − il_teardown_interface(il, vif, true); | |
| 4689 | 4689 | vif->type = newtype; |
| 4690 | 4690 | vif->p2p = false; |
| 4691 | − err = il_set_mode(il); | |
| 4692 | − WARN_ON(err); | |
| 4693 | − /* | |
| 4694 | − * We've switched internally, but submitting to the | |
| 4695 | − * device may have failed for some reason. Mask this | |
| 4696 | − * error, because otherwise mac80211 will not switch | |
| 4697 | − * (and set the interface type back) and we'll be | |
| 4698 | − * out of sync with it. | |
| 4699 | − */ | |
| 4691 | + il->iw_mode = newtype; | |
| 4692 | + il_teardown_interface(il, vif); | |
| 4700 | 4693 | err = 0; |
| 4701 | 4694 | |
| 4702 | 4695 | out: |
| @@ -4707,6 +4700,42 @@ out: · 4 unmodified lines | ||
| 4707 | 4700 | } |
| 4708 | 4701 | EXPORT_SYMBOL(il_mac_change_interface); |
| 4709 | 4702 | |
| 4703 | +void | |
| 4704 | +il_mac_flush(struct ieee80211_hw *hw, bool drop) | |
| 4705 | +{ | |
| 4706 | + struct il_priv *il = hw->priv; | |
| 4707 | + unsigned long timeout = jiffies + msecs_to_jiffies(500); | |
| 4708 | + int i; | |
| 4709 | + | |
| 4710 | + mutex_lock(&il->mutex); | |
| 4711 | + D_MAC80211("enter\n"); | |
| 4712 | + | |
| 4713 | + if (il->txq == NULL) | |
| 4714 | + goto out; | |
| 4715 | + | |
| 4716 | + for (i = 0; i < il->hw_params.max_txq_num; i++) { | |
| 4717 | + struct il_queue *q; | |
| 4718 | + | |
| 4719 | + if (i == il->cmd_queue) | |
| 4720 | + continue; | |
| 4721 | + | |
| 4722 | + q = &il->txq[i].q; | |
| 4723 | + if (q->read_ptr == q->write_ptr) | |
| 4724 | + continue; | |
| 4725 | + | |
| 4726 | + if (time_after(jiffies, timeout)) { | |
| 4727 | + IL_ERR("Failed to flush queue %d\n", q->id); | |
| 4728 | + break; | |
| 4729 | + } | |
| 4730 | + | |
| 4731 | + msleep(20); | |
| 4732 | + } | |
| 4733 | +out: | |
| 4734 | + D_MAC80211("leave\n"); | |
| 4735 | + mutex_unlock(&il->mutex); | |
| 4736 | +} | |
| 4737 | +EXPORT_SYMBOL(il_mac_flush); | |
| 4738 | + | |
| 4710 | 4739 | /* |
| 4711 | 4740 | * On every watchdog tick we check (latest) time stamp. If it does not |
| 4712 | 4741 | * change during timeout period and queue is not empty we reset firmware. |
| @@ -1723,6 +1723,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw, · 1722 unmodified lines | ||
| 1723 | 1723 | struct ieee80211_vif *vif); |
| 1724 | 1724 | int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1725 | 1725 | enum nl80211_iftype newtype, bool newp2p); |
| 1726 | +void il_mac_flush(struct ieee80211_hw *hw, bool drop); | |
| 1726 | 1727 | int il_alloc_txq_mem(struct il_priv *il); |
| 1727 | 1728 | void il_free_txq_mem(struct il_priv *il); |
| 1728 | 1729 | |
| @@ -3695,7 +3695,7 @@ struct iwl_bt_uart_msg { · 3694 unmodified lines | ||
| 3695 | 3695 | u8 frame5; |
| 3696 | 3696 | u8 frame6; |
| 3697 | 3697 | u8 frame7; |
| 3698 | −} __attribute__((packed)); | |
| 3698 | +} __packed; | |
| 3699 | 3699 | |
| 3700 | 3700 | struct iwl_bt_coex_profile_notif { |
| 3701 | 3701 | struct iwl_bt_uart_msg last_bt_uart_msg; |
| @@ -3703,7 +3703,7 @@ struct iwl_bt_coex_profile_notif { · 1 unmodified line | ||
| 3703 | 3703 | u8 bt_traffic_load; /* 0 .. 3? */ |
| 3704 | 3704 | u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */ |
| 3705 | 3705 | u8 reserved; |
| 3706 | −} __attribute__((packed)); | |
| 3706 | +} __packed; | |
| 3707 | 3707 | |
| 3708 | 3708 | #define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS 0 |
| 3709 | 3709 | #define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK 0x1 |
| @@ -3752,7 +3752,7 @@ enum bt_coex_prio_table_priorities { · 42 unmodified lines | ||
| 3752 | 3752 | |
| 3753 | 3753 | struct iwl_bt_coex_prio_table_cmd { |
| 3754 | 3754 | u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX]; |
| 3755 | −} __attribute__((packed)); | |
| 3755 | +} __packed; | |
| 3756 | 3756 | |
| 3757 | 3757 | #define IWL_BT_COEX_ENV_CLOSE 0 |
| 3758 | 3758 | #define IWL_BT_COEX_ENV_OPEN 1 |
| @@ -3764,7 +3764,7 @@ struct iwl_bt_coex_prot_env_cmd { · 5 unmodified lines | ||
| 3764 | 3764 | u8 action; /* 0 = closed, 1 = open */ |
| 3765 | 3765 | u8 type; /* 0 .. 15 */ |
| 3766 | 3766 | u8 reserved[2]; |
| 3767 | −} __attribute__((packed)); | |
| 3767 | +} __packed; | |
| 3768 | 3768 | |
| 3769 | 3769 | /* |
| 3770 | 3770 | * REPLY_D3_CONFIG |
| @@ -157,7 +157,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, · 156 unmodified lines | ||
| 157 | 157 | sram = priv->dbgfs_sram_offset & ~0x3; |
| 158 | 158 | |
| 159 | 159 | /* read the first u32 from sram */ |
| 160 | − val = iwl_read_targ_mem(priv->trans, sram); | |
| 160 | + val = iwl_trans_read_mem32(priv->trans, sram); | |
| 161 | 161 | |
| 162 | 162 | for (; len; len--) { |
| 163 | 163 | /* put the address at the start of every line */ |
| @@ -176,7 +176,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, · 12 unmodified lines | ||
| 176 | 176 | if (++offset == 4) { |
| 177 | 177 | sram += 4; |
| 178 | 178 | offset = 0; |
| 179 | − val = iwl_read_targ_mem(priv->trans, sram); | |
| 179 | + val = iwl_trans_read_mem32(priv->trans, sram); | |
| 180 | 180 | } |
| 181 | 181 | |
| 182 | 182 | /* put in extra spaces and split lines for human readability */ |
| @@ -69,7 +69,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = { · 68 unmodified lines | ||
| 69 | 69 | /* Set led register off */ |
| 70 | 70 | void iwlagn_led_enable(struct iwl_priv *priv) |
| 71 | 71 | { |
| 72 | − iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON); | |
| 72 | + iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON); | |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | 75 | /* |
| @@ -206,7 +206,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, · 205 unmodified lines | ||
| 206 | 206 | |
| 207 | 207 | #ifdef CONFIG_PM_SLEEP |
| 208 | 208 | if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len && |
| 209 | − priv->trans->ops->wowlan_suspend && | |
| 209 | + priv->trans->ops->d3_suspend && | |
| 210 | + priv->trans->ops->d3_resume && | |
| 210 | 211 | device_can_wakeup(priv->trans->dev)) { |
| 211 | 212 | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | |
| 212 | 213 | WIPHY_WOWLAN_DISCONNECT | |
| @@ -426,7 +427,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, · 213 unmodified lines | ||
| 426 | 427 | if (ret) |
| 427 | 428 | goto error; |
| 428 | 429 | |
| 429 | − iwl_trans_wowlan_suspend(priv->trans); | |
| 430 | + iwl_trans_d3_suspend(priv->trans); | |
| 430 | 431 | |
| 431 | 432 | goto out; |
| 432 | 433 | |
| @@ -459,11 +460,11 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) · 26 unmodified lines | ||
| 459 | 460 | base = priv->device_pointers.error_event_table; |
| 460 | 461 | if (iwlagn_hw_valid_rtc_data_addr(base)) { |
| 461 | 462 | spin_lock_irqsave(&priv->trans->reg_lock, flags); |
| 462 | − ret = iwl_grab_nic_access_silent(priv->trans); | |
| 463 | − if (likely(ret == 0)) { | |
| 463 | + if (iwl_trans_grab_nic_access(priv->trans, true)) { | |
| 464 | 464 | iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); |
| 465 | 465 | status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); |
| 466 | − iwl_release_nic_access(priv->trans); | |
| 466 | + iwl_trans_release_nic_access(priv->trans); | |
| 467 | + ret = 0; | |
| 467 | 468 | } |
| 468 | 469 | spin_unlock_irqrestore(&priv->trans->reg_lock, flags); |
| 469 | 470 | |
| @@ -479,7 +480,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) · 9 unmodified lines | ||
| 479 | 480 | } |
| 480 | 481 | |
| 481 | 482 | if (priv->wowlan_sram) |
| 482 | − _iwl_read_targ_mem_dwords( | |
| 483 | + iwl_trans_read_mem( | |
| 483 | 484 | priv->trans, 0x800000, |
| 484 | 485 | priv->wowlan_sram, |
| 485 | 486 | img->sec[IWL_UCODE_SECTION_DATA].len / 4); |
| @@ -520,9 +521,6 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw, · 34 unmodified lines | ||
| 520 | 521 | { |
| 521 | 522 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
| 522 | 523 | |
| 523 | − IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, | |
| 524 | − ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); | |
| 525 | − | |
| 526 | 524 | if (iwlagn_tx_skb(priv, control->sta, skb)) |
| 527 | 525 | ieee80211_free_txskb(hw, skb); |
| 528 | 526 | } |
| @@ -354,7 +354,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, · 353 unmodified lines | ||
| 354 | 354 | |
| 355 | 355 | /* Make sure device is powered up for SRAM reads */ |
| 356 | 356 | spin_lock_irqsave(&priv->trans->reg_lock, reg_flags); |
| 357 | − if (unlikely(!iwl_grab_nic_access(priv->trans))) { | |
| 357 | + if (!iwl_trans_grab_nic_access(priv->trans, false)) { | |
| 358 | 358 | spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); |
| 359 | 359 | return; |
| 360 | 360 | } |
| @@ -388,7 +388,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, · 27 unmodified lines | ||
| 388 | 388 | } |
| 389 | 389 | } |
| 390 | 390 | /* Allow device to power down */ |
| 391 | − iwl_release_nic_access(priv->trans); | |
| 391 | + iwl_trans_release_nic_access(priv->trans); | |
| 392 | 392 | spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); |
| 393 | 393 | } |
| 394 | 394 | |
| @@ -408,7 +408,8 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) · 13 unmodified lines | ||
| 408 | 408 | |
| 409 | 409 | base = priv->device_pointers.log_event_table; |
| 410 | 410 | if (iwlagn_hw_valid_rtc_data_addr(base)) { |
| 411 | − iwl_read_targ_mem_bytes(priv->trans, base, &read, sizeof(read)); | |
| 411 | + iwl_trans_read_mem_bytes(priv->trans, base, | |
| 412 | + &read, sizeof(read)); | |
| 412 | 413 | capacity = read.capacity; |
| 413 | 414 | mode = read.mode; |
| 414 | 415 | num_wraps = read.wrap_counter; |
| @@ -1627,7 +1628,7 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) · 1212 unmodified lines | ||
| 1627 | 1628 | } |
| 1628 | 1629 | |
| 1629 | 1630 | /*TODO: Update dbgfs with ISR error stats obtained below */ |
| 1630 | − iwl_read_targ_mem_bytes(trans, base, &table, sizeof(table)); | |
| 1631 | + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); | |
| 1631 | 1632 | |
| 1632 | 1633 | if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { |
| 1633 | 1634 | IWL_ERR(trans, "Start IWL Error Log Dump:\n"); |
| @@ -1717,7 +1718,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, · 83 unmodified lines | ||
| 1717 | 1718 | |
| 1718 | 1719 | /* Make sure device is powered up for SRAM reads */ |
| 1719 | 1720 | spin_lock_irqsave(&trans->reg_lock, reg_flags); |
| 1720 | − if (unlikely(!iwl_grab_nic_access(trans))) | |
| 1721 | + if (!iwl_trans_grab_nic_access(trans, false)) | |
| 1721 | 1722 | goto out_unlock; |
| 1722 | 1723 | |
| 1723 | 1724 | /* Set starting address; reads will auto-increment */ |
| @@ -1756,7 +1757,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, · 32 unmodified lines | ||
| 1756 | 1757 | } |
| 1757 | 1758 | |
| 1758 | 1759 | /* Allow device to power down */ |
| 1759 | − iwl_release_nic_access(trans); | |
| 1760 | + iwl_trans_release_nic_access(trans); | |
| 1760 | 1761 | out_unlock: |
| 1761 | 1762 | spin_unlock_irqrestore(&trans->reg_lock, reg_flags); |
| 1762 | 1763 | return pos; |
| @@ -1835,10 +1836,10 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, · 72 unmodified lines | ||
| 1835 | 1836 | } |
| 1836 | 1837 | |
| 1837 | 1838 | /* event log header */ |
| 1838 | − capacity = iwl_read_targ_mem(trans, base); | |
| 1839 | − mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32))); | |
| 1840 | − num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32))); | |
| 1841 | − next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32))); | |
| 1839 | + capacity = iwl_trans_read_mem32(trans, base); | |
| 1840 | + mode = iwl_trans_read_mem32(trans, base + (1 * sizeof(u32))); | |
| 1841 | + num_wraps = iwl_trans_read_mem32(trans, base + (2 * sizeof(u32))); | |
| 1842 | + next_entry = iwl_trans_read_mem32(trans, base + (3 * sizeof(u32))); | |
| 1842 | 1843 | |
| 1843 | 1844 | if (capacity > logsize) { |
| 1844 | 1845 | IWL_ERR(priv, "Log capacity %d is bogus, limit to %d " |
| @@ -186,8 +186,8 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) · 185 unmodified lines | ||
| 186 | 186 | } |
| 187 | 187 | iwl_read32(priv->trans, CSR_UCODE_DRV_GP1); |
| 188 | 188 | spin_lock_irqsave(&priv->trans->reg_lock, flags); |
| 189 | − if (likely(iwl_grab_nic_access(priv->trans))) | |
| 190 | − iwl_release_nic_access(priv->trans); | |
| 189 | + if (iwl_trans_grab_nic_access(priv->trans, false)) | |
| 190 | + iwl_trans_release_nic_access(priv->trans); | |
| 191 | 191 | spin_unlock_irqrestore(&priv->trans->reg_lock, flags); |
| 192 | 192 | |
| 193 | 193 | /* Reschedule the ct_kill timer to occur in |
| @@ -231,13 +231,11 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv, · 230 unmodified lines | ||
| 231 | 231 | memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); |
| 232 | 232 | if (info->flags & IEEE80211_TX_CTL_AMPDU) |
| 233 | 233 | tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; |
| 234 | − IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n"); | |
| 235 | 234 | break; |
| 236 | 235 | |
| 237 | 236 | case WLAN_CIPHER_SUITE_TKIP: |
| 238 | 237 | tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; |
| 239 | 238 | ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key); |
| 240 | − IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n"); | |
| 241 | 239 | break; |
| 242 | 240 | |
| 243 | 241 | case WLAN_CIPHER_SUITE_WEP104: |
| @@ -355,8 +353,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, · 111 unmodified lines | ||
| 355 | 353 | } |
| 356 | 354 | } |
| 357 | 355 | |
| 358 | − IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); | |
| 359 | − | |
| 360 | 356 | if (sta) |
| 361 | 357 | sta_priv = (void *)sta->drv_priv; |
| 362 | 358 | |
| @@ -472,6 +468,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, · 109 unmodified lines | ||
| 472 | 468 | WARN_ON_ONCE(is_agg && |
| 473 | 469 | priv->queue_to_mac80211[txq_id] != info->hw_queue); |
| 474 | 470 | |
| 471 | + IWL_DEBUG_TX(priv, "TX to [%d|%d] Q:%d - seq: 0x%x\n", sta_id, tid, | |
| 472 | + txq_id, seq_number); | |
| 473 | + | |
| 475 | 474 | if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id)) |
| 476 | 475 | goto drop_unlock_sta; |
| 477 | 476 | |
| @@ -541,9 +540,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, · 63 unmodified lines | ||
| 541 | 540 | spin_lock_bh(&priv->sta_lock); |
| 542 | 541 | |
| 543 | 542 | tid_data = &priv->tid_data[sta_id][tid]; |
| 544 | − txq_id = priv->tid_data[sta_id][tid].agg.txq_id; | |
| 543 | + txq_id = tid_data->agg.txq_id; | |
| 545 | 544 | |
| 546 | − switch (priv->tid_data[sta_id][tid].agg.state) { | |
| 545 | + switch (tid_data->agg.state) { | |
| 547 | 546 | case IWL_EMPTYING_HW_QUEUE_ADDBA: |
| 548 | 547 | /* |
| 549 | 548 | * This can happen if the peer stops aggregation |
| @@ -563,9 +562,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, · 13 unmodified lines | ||
| 563 | 562 | case IWL_AGG_ON: |
| 564 | 563 | break; |
| 565 | 564 | default: |
| 566 | − IWL_WARN(priv, "Stopping AGG while state not ON " | |
| 567 | − "or starting for %d on %d (%d)\n", sta_id, tid, | |
| 568 | − priv->tid_data[sta_id][tid].agg.state); | |
| 565 | + IWL_WARN(priv, | |
| 566 | + "Stopping AGG while state not ON or starting for %d on %d (%d)\n", | |
| 567 | + sta_id, tid, tid_data->agg.state); | |
| 569 | 568 | spin_unlock_bh(&priv->sta_lock); |
| 570 | 569 | return 0; |
| 571 | 570 | } |
| @@ -578,12 +577,11 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, · 6 unmodified lines | ||
| 578 | 577 | "stopping AGG on STA/TID %d/%d but hwq %d not used\n", |
| 579 | 578 | sta_id, tid, txq_id); |
| 580 | 579 | } else if (tid_data->agg.ssn != tid_data->next_reclaimed) { |
| 581 | − IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, " | |
| 582 | − "next_recl = %d\n", | |
| 580 | + IWL_DEBUG_TX_QUEUES(priv, | |
| 581 | + "Can't proceed: ssn %d, next_recl = %d\n", | |
| 583 | 582 | tid_data->agg.ssn, |
| 584 | 583 | tid_data->next_reclaimed); |
| 585 | − priv->tid_data[sta_id][tid].agg.state = | |
| 586 | − IWL_EMPTYING_HW_QUEUE_DELBA; | |
| 584 | + tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_DELBA; | |
| 587 | 585 | spin_unlock_bh(&priv->sta_lock); |
| 588 | 586 | return 0; |
| 589 | 587 | } |
| @@ -591,8 +589,8 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, · 1 unmodified line | ||
| 591 | 589 | IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n", |
| 592 | 590 | tid_data->agg.ssn); |
| 593 | 591 | turn_off: |
| 594 | − agg_state = priv->tid_data[sta_id][tid].agg.state; | |
| 595 | − priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF; | |
| 592 | + agg_state = tid_data->agg.state; | |
| 593 | + tid_data->agg.state = IWL_AGG_OFF; | |
| 596 | 594 | |
| 597 | 595 | spin_unlock_bh(&priv->sta_lock); |
| 598 | 596 | |
| @@ -954,12 +952,6 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, · 355 unmodified lines | ||
| 954 | 952 | if (status & (AGG_TX_STATE_FEW_BYTES_MSK | |
| 955 | 953 | AGG_TX_STATE_ABORT_MSK)) |
| 956 | 954 | continue; |
| 957 | − | |
| 958 | − IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), " | |
| 959 | − "try-count (0x%08x)\n", | |
| 960 | − iwl_get_agg_tx_fail_reason(fstatus), | |
| 961 | − fstatus & AGG_TX_STATUS_MSK, | |
| 962 | − fstatus & AGG_TX_TRY_MSK); | |
| 963 | 955 | } |
| 964 | 956 | } |
| 965 | 957 | |
| @@ -1079,6 +1071,8 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv, · 113 unmodified lines | ||
| 1079 | 1071 | { |
| 1080 | 1072 | u16 status = le16_to_cpu(tx_resp->status.status); |
| 1081 | 1073 | |
| 1074 | + info->flags &= ~IEEE80211_TX_CTL_AMPDU; | |
| 1075 | + | |
| 1082 | 1076 | info->status.rates[0].count = tx_resp->failure_frame + 1; |
| 1083 | 1077 | info->flags |= iwl_tx_status_to_mac80211(status); |
| 1084 | 1078 | iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), |
| @@ -1151,13 +1145,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, · 66 unmodified lines | ||
| 1151 | 1145 | next_reclaimed = ssn; |
| 1152 | 1146 | } |
| 1153 | 1147 | |
| 1154 | − if (tid != IWL_TID_NON_QOS) { | |
| 1155 | − priv->tid_data[sta_id][tid].next_reclaimed = | |
| 1156 | − next_reclaimed; | |
| 1157 | − IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", | |
| 1158 | − next_reclaimed); | |
| 1159 | − } | |
| 1160 | − | |
| 1161 | 1148 | iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs); |
| 1162 | 1149 | |
| 1163 | 1150 | iwlagn_check_ratid_empty(priv, sta_id, tid); |
| @@ -1208,21 +1195,49 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, · 44 unmodified lines | ||
| 1208 | 1195 | if (!is_agg) |
| 1209 | 1196 | iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); |
| 1210 | 1197 | |
| 1198 | + /* | |
| 1199 | + * W/A for FW bug - the seq_ctl isn't updated when the | |
| 1200 | + * queues are flushed. Fetch it from the packet itself | |
| 1201 | + */ | |
| 1202 | + if (!is_agg && status == TX_STATUS_FAIL_FIFO_FLUSHED) { | |
| 1203 | + next_reclaimed = le16_to_cpu(hdr->seq_ctrl); | |
| 1204 | + next_reclaimed = | |
| 1205 | + SEQ_TO_SN(next_reclaimed + 0x10); | |
| 1206 | + } | |
| 1207 | + | |
| 1211 | 1208 | is_offchannel_skb = |
| 1212 | 1209 | (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); |
| 1213 | 1210 | freed++; |
| 1214 | 1211 | } |
| 1215 | 1212 | |
| 1216 | − WARN_ON(!is_agg && freed != 1); | |
| 1213 | + if (tid != IWL_TID_NON_QOS) { | |
| 1214 | + priv->tid_data[sta_id][tid].next_reclaimed = | |
| 1215 | + next_reclaimed; | |
| 1216 | + IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", | |
| 1217 | + next_reclaimed); | |
| 1218 | + } | |
| 1219 | + | |
| 1220 | + if (!is_agg && freed != 1) | |
| 1221 | + IWL_ERR(priv, "Q: %d, freed %d\n", txq_id, freed); | |
| 1217 | 1222 | |
| 1218 | 1223 | /* |
| 1219 | 1224 | * An offchannel frame can be send only on the AUX queue, where |
| 1220 | 1225 | * there is no aggregation (and reordering) so it only is single |
| 1221 | 1226 | * skb is expected to be processed. |
| 1222 | 1227 | */ |
| 1223 | − WARN_ON(is_offchannel_skb && freed != 1); | |
| 1228 | + if (is_offchannel_skb && freed != 1) | |
| 1229 | + IWL_ERR(priv, "OFFCHANNEL SKB freed %d\n", freed); | |
| 1224 | 1230 | } |
| 1225 | 1231 | |
| 1232 | + IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x)\n", txq_id, | |
| 1233 | + iwl_get_tx_fail_reason(status), status); | |
| 1234 | + | |
| 1235 | + IWL_DEBUG_TX_REPLY(priv, | |
| 1236 | + "\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d seq_ctl=0x%x\n", | |
| 1237 | + le32_to_cpu(tx_resp->rate_n_flags), | |
| 1238 | + tx_resp->failure_frame, SEQ_TO_INDEX(sequence), ssn, | |
| 1239 | + le16_to_cpu(tx_resp->seq_ctl)); | |
| 1240 | + | |
| 1226 | 1241 | iwl_check_abort_status(priv, tx_resp->frame_count, status); |
| 1227 | 1242 | spin_unlock(&priv->sta_lock); |
| 1228 | 1243 | |
| @@ -286,89 +286,6 @@ static int iwl_alive_notify(struct iwl_priv *priv) · 285 unmodified lines | ||
| 286 | 286 | return iwl_send_calib_results(priv); |
| 287 | 287 | } |
| 288 | 288 | |
| 289 | − | |
| 290 | −/** | |
| 291 | − * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, | |
| 292 | − * using sample data 100 bytes apart. If these sample points are good, | |
| 293 | − * it's a pretty good bet that everything between them is good, too. | |
| 294 | − */ | |
| 295 | −static int iwl_verify_sec_sparse(struct iwl_priv *priv, | |
| 296 | − const struct fw_desc *fw_desc) | |
| 297 | −{ | |
| 298 | − __le32 *image = (__le32 *)fw_desc->data; | |
| 299 | − u32 len = fw_desc->len; | |
| 300 | − u32 val; | |
| 301 | − u32 i; | |
| 302 | − | |
| 303 | − IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len); | |
| 304 | − | |
| 305 | − for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { | |
| 306 | − /* read data comes through single port, auto-incr addr */ | |
| 307 | − /* NOTE: Use the debugless read so we don't flood kernel log | |
| 308 | − * if IWL_DL_IO is set */ | |
| 309 | − iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR, | |
| 310 | − i + fw_desc->offset); | |
| 311 | − val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); | |
| 312 | − if (val != le32_to_cpu(*image)) | |
| 313 | − return -EIO; | |
| 314 | − } | |
| 315 | − | |
| 316 | − return 0; | |
| 317 | −} | |
| 318 | − | |
| 319 | −static void iwl_print_mismatch_sec(struct iwl_priv *priv, | |
| 320 | − const struct fw_desc *fw_desc) | |
| 321 | −{ | |
| 322 | − __le32 *image = (__le32 *)fw_desc->data; | |
| 323 | − u32 len = fw_desc->len; | |
| 324 | − u32 val; | |
| 325 | − u32 offs; | |
| 326 | − int errors = 0; | |
| 327 | − | |
| 328 | − IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len); | |
| 329 | − | |
| 330 | − iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR, | |
| 331 | − fw_desc->offset); | |
| 332 | − | |
| 333 | − for (offs = 0; | |
| 334 | − offs < len && errors < 20; | |
| 335 | − offs += sizeof(u32), image++) { | |
| 336 | − /* read data comes through single port, auto-incr addr */ | |
| 337 | − val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); | |
| 338 | − if (val != le32_to_cpu(*image)) { | |
| 339 | − IWL_ERR(priv, "uCode INST section at " | |
| 340 | − "offset 0x%x, is 0x%x, s/b 0x%x\n", | |
| 341 | − offs, val, le32_to_cpu(*image)); | |
| 342 | − errors++; | |
| 343 | − } | |
| 344 | − } | |
| 345 | −} | |
| 346 | − | |
| 347 | −/** | |
| 348 | − * iwl_verify_ucode - determine which instruction image is in SRAM, | |
| 349 | − * and verify its contents | |
| 350 | − */ | |
| 351 | −static int iwl_verify_ucode(struct iwl_priv *priv, | |
| 352 | − enum iwl_ucode_type ucode_type) | |
| 353 | −{ | |
| 354 | − const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type); | |
| 355 | − | |
| 356 | − if (!img) { | |
| 357 | − IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type); | |
| 358 | − return -EINVAL; | |
| 359 | − } | |
| 360 | − | |
| 361 | − if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) { | |
| 362 | − IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n"); | |
| 363 | − return 0; | |
| 364 | − } | |
| 365 | − | |
| 366 | − IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); | |
| 367 | − | |
| 368 | − iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]); | |
| 369 | − return -EIO; | |
| 370 | −} | |
| 371 | − | |
| 372 | 289 | struct iwl_alive_data { |
| 373 | 290 | bool valid; |
| 374 | 291 | u8 subtype; |
| @@ -426,7 +343,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, · 51 unmodified lines | ||
| 426 | 343 | alive_cmd, ARRAY_SIZE(alive_cmd), |
| 427 | 344 | iwl_alive_fn, &alive_data); |
| 428 | 345 | |
| 429 | − ret = iwl_trans_start_fw(priv->trans, fw); | |
| 346 | + ret = iwl_trans_start_fw(priv->trans, fw, false); | |
| 430 | 347 | if (ret) { |
| 431 | 348 | priv->cur_ucode = old_type; |
| 432 | 349 | iwl_remove_notification(&priv->notif_wait, &alive_wait); |
| @@ -450,18 +367,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, · 17 unmodified lines | ||
| 450 | 367 | return -EIO; |
| 451 | 368 | } |
| 452 | 369 | |
| 453 | − /* | |
| 454 | − * This step takes a long time (60-80ms!!) and | |
| 455 | − * WoWLAN image should be loaded quickly, so | |
| 456 | − * skip it for WoWLAN. | |
| 457 | − */ | |
| 458 | 370 | if (ucode_type != IWL_UCODE_WOWLAN) { |
| 459 | − ret = iwl_verify_ucode(priv, ucode_type); | |
| 460 | − if (ret) { | |
| 461 | − priv->cur_ucode = old_type; | |
| 462 | − return ret; | |
| 463 | − } | |
| 464 | − | |
| 465 | 371 | /* delay a bit to give rfkill time to run */ |
| 466 | 372 | msleep(5); |
| 467 | 373 | } |
| @@ -381,8 +381,8 @@ · 380 unmodified lines | ||
| 381 | 381 | |
| 382 | 382 | /* LED */ |
| 383 | 383 | #define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF) |
| 384 | −#define CSR_LED_REG_TRUN_ON (0x78) | |
| 385 | −#define CSR_LED_REG_TRUN_OFF (0x38) | |
| 384 | +#define CSR_LED_REG_TURN_ON (0x60) | |
| 385 | +#define CSR_LED_REG_TURN_OFF (0x20) | |
| 386 | 386 | |
| 387 | 387 | /* ANA_PLL */ |
| 388 | 388 | #define CSR50_ANA_PLL_CFG_VAL (0x00880300) |
| @@ -225,6 +225,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) · 224 unmodified lines | ||
| 225 | 225 | #define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008) |
| 226 | 226 | #define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG) |
| 227 | 227 | |
| 228 | +#define FW_RSCSR_CHNL0_RXDCB_RDPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x00c) | |
| 229 | +#define FH_RSCSR_CHNL0_RDPTR FW_RSCSR_CHNL0_RXDCB_RDPTR_REG | |
| 228 | 230 | |
| 229 | 231 | /** |
| 230 | 232 | * Rx Config/Status Registers (RCSR) |
| @@ -257,6 +259,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) · 26 unmodified lines | ||
| 257 | 259 | #define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND) |
| 258 | 260 | |
| 259 | 261 | #define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0) |
| 262 | +#define FH_MEM_RCSR_CHNL0_RBDCB_WPTR (FH_MEM_RCSR_CHNL0 + 0x8) | |
| 263 | +#define FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ (FH_MEM_RCSR_CHNL0 + 0x10) | |
| 260 | 264 | |
| 261 | 265 | #define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */ |
| 262 | 266 | #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK (0x00001000) /* bits 12 */ |
| @@ -35,12 +35,12 @@ · 34 unmodified lines | ||
| 35 | 35 | |
| 36 | 36 | #define IWL_POLL_INTERVAL 10 /* microseconds */ |
| 37 | 37 | |
| 38 | −static inline void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) | |
| 38 | +void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) | |
| 39 | 39 | { |
| 40 | 40 | iwl_write32(trans, reg, iwl_read32(trans, reg) | mask); |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | −static inline void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) | |
| 43 | +void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) | |
| 44 | 44 | { |
| 45 | 45 | iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask); |
| 46 | 46 | } |
| @@ -99,86 +99,16 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr, · 52 unmodified lines | ||
| 99 | 99 | } |
| 100 | 100 | EXPORT_SYMBOL_GPL(iwl_poll_bit); |
| 101 | 101 | |
| 102 | −int iwl_grab_nic_access_silent(struct iwl_trans *trans) | |
| 103 | −{ | |
| 104 | − int ret; | |
| 105 | − | |
| 106 | − lockdep_assert_held(&trans->reg_lock); | |
| 107 | − | |
| 108 | − /* this bit wakes up the NIC */ | |
| 109 | − __iwl_set_bit(trans, CSR_GP_CNTRL, | |
| 110 | − CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | |
| 111 | − | |
| 112 | − /* | |
| 113 | − * These bits say the device is running, and should keep running for | |
| 114 | − * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), | |
| 115 | − * but they do not indicate that embedded SRAM is restored yet; | |
| 116 | − * 3945 and 4965 have volatile SRAM, and must save/restore contents | |
| 117 | − * to/from host DRAM when sleeping/waking for power-saving. | |
| 118 | − * Each direction takes approximately 1/4 millisecond; with this | |
| 119 | − * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a | |
| 120 | − * series of register accesses are expected (e.g. reading Event Log), | |
| 121 | − * to keep device from sleeping. | |
| 122 | − * | |
| 123 | − * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that | |
| 124 | − * SRAM is okay/restored. We don't check that here because this call | |
| 125 | − * is just for hardware register access; but GP1 MAC_SLEEP check is a | |
| 126 | − * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). | |
| 127 | − * | |
| 128 | − * 5000 series and later (including 1000 series) have non-volatile SRAM, | |
| 129 | − * and do not save/restore SRAM when power cycling. | |
| 130 | − */ | |
| 131 | − ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | |
| 132 | − CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, | |
| 133 | − (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | | |
| 134 | − CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); | |
| 135 | − if (ret < 0) { | |
| 136 | − iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); | |
| 137 | − return -EIO; | |
| 138 | − } | |
| 139 | − | |
| 140 | − return 0; | |
| 141 | −} | |
| 142 | −EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent); | |
| 143 | − | |
| 144 | −bool iwl_grab_nic_access(struct iwl_trans *trans) | |
| 145 | −{ | |
| 146 | − int ret = iwl_grab_nic_access_silent(trans); | |
| 147 | − if (unlikely(ret)) { | |
| 148 | − u32 val = iwl_read32(trans, CSR_GP_CNTRL); | |
| 149 | − WARN_ONCE(1, "Timeout waiting for hardware access " | |
| 150 | − "(CSR_GP_CNTRL 0x%08x)\n", val); | |
| 151 | − return false; | |
| 152 | − } | |
| 153 | − | |
| 154 | − return true; | |
| 155 | −} | |
| 156 | −EXPORT_SYMBOL_GPL(iwl_grab_nic_access); | |
| 157 | − | |
| 158 | −void iwl_release_nic_access(struct iwl_trans *trans) | |
| 159 | −{ | |
| 160 | − lockdep_assert_held(&trans->reg_lock); | |
| 161 | − __iwl_clear_bit(trans, CSR_GP_CNTRL, | |
| 162 | − CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | |
| 163 | − /* | |
| 164 | − * Above we read the CSR_GP_CNTRL register, which will flush | |
| 165 | − * any previous writes, but we need the write that clears the | |
| 166 | − * MAC_ACCESS_REQ bit to be performed before any other writes | |
| 167 | − * scheduled on different CPUs (after we drop reg_lock). | |
| 168 | − */ | |
| 169 | − mmiowb(); | |
| 170 | −} | |
| 171 | −EXPORT_SYMBOL_GPL(iwl_release_nic_access); | |
| 172 | − | |
| 173 | 102 | u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) |
| 174 | 103 | { |
| 175 | − u32 value; | |
| 104 | + u32 value = 0x5a5a5a5a; | |
| 176 | 105 | unsigned long flags; |
| 177 | 106 | |
| 178 | 107 | spin_lock_irqsave(&trans->reg_lock, flags); |
| 179 | − iwl_grab_nic_access(trans); | |
| 180 | − value = iwl_read32(trans, reg); | |
| 181 | − iwl_release_nic_access(trans); | |
| 108 | + if (iwl_trans_grab_nic_access(trans, false)) { | |
| 109 | + value = iwl_read32(trans, reg); | |
| 110 | + iwl_trans_release_nic_access(trans); | |
| 111 | + } | |
| 182 | 112 | spin_unlock_irqrestore(&trans->reg_lock, flags); |
| 183 | 113 | |
| 184 | 114 | return value; |
| @@ -190,9 +120,9 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) · 5 unmodified lines | ||
| 190 | 120 | unsigned long flags; |
| 191 | 121 | |
| 192 | 122 | spin_lock_irqsave(&trans->reg_lock, flags); |
| 193 | − if (likely(iwl_grab_nic_access(trans))) { | |
| 123 | + if (iwl_trans_grab_nic_access(trans, false)) { | |
| 194 | 124 | iwl_write32(trans, reg, value); |
| 195 | − iwl_release_nic_access(trans); | |
| 125 | + iwl_trans_release_nic_access(trans); | |
| 196 | 126 | } |
| 197 | 127 | spin_unlock_irqrestore(&trans->reg_lock, flags); |
| 198 | 128 | } |
| @@ -230,12 +160,13 @@ static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) · 31 unmodified lines | ||
| 230 | 160 | u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) |
| 231 | 161 | { |
| 232 | 162 | unsigned long flags; |
| 233 | − u32 val; | |
| 163 | + u32 val = 0x5a5a5a5a; | |
| 234 | 164 | |
| 235 | 165 | spin_lock_irqsave(&trans->reg_lock, flags); |
| 236 | − iwl_grab_nic_access(trans); | |
| 237 | − val = __iwl_read_prph(trans, ofs); | |
| 238 | − iwl_release_nic_access(trans); | |
| 166 | + if (iwl_trans_grab_nic_access(trans, false)) { | |
| 167 | + val = __iwl_read_prph(trans, ofs); | |
| 168 | + iwl_trans_release_nic_access(trans); | |
| 169 | + } | |
| 239 | 170 | spin_unlock_irqrestore(&trans->reg_lock, flags); |
| 240 | 171 | return val; |
| 241 | 172 | } |
| @@ -246,9 +177,9 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) · 4 unmodified lines | ||
| 246 | 177 | unsigned long flags; |
| 247 | 178 | |
| 248 | 179 | spin_lock_irqsave(&trans->reg_lock, flags); |
| 249 | − if (likely(iwl_grab_nic_access(trans))) { | |
| 180 | + if (iwl_trans_grab_nic_access(trans, false)) { | |
| 250 | 181 | __iwl_write_prph(trans, ofs, val); |
| 251 | − iwl_release_nic_access(trans); | |
| 182 | + iwl_trans_release_nic_access(trans); | |
| 252 | 183 | } |
| 253 | 184 | spin_unlock_irqrestore(&trans->reg_lock, flags); |
| 254 | 185 | } |
| @@ -259,10 +190,10 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) · 4 unmodified lines | ||
| 259 | 190 | unsigned long flags; |
| 260 | 191 | |
| 261 | 192 | spin_lock_irqsave(&trans->reg_lock, flags); |
| 262 | − if (likely(iwl_grab_nic_access(trans))) { | |
| 193 | + if (iwl_trans_grab_nic_access(trans, false)) { | |
| 263 | 194 | __iwl_write_prph(trans, ofs, |
| 264 | 195 | __iwl_read_prph(trans, ofs) | mask); |
| 265 | − iwl_release_nic_access(trans); | |
| 196 | + iwl_trans_release_nic_access(trans); | |
| 266 | 197 | } |
| 267 | 198 | spin_unlock_irqrestore(&trans->reg_lock, flags); |
| 268 | 199 | } |
| @@ -274,10 +205,10 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, · 5 unmodified lines | ||
| 274 | 205 | unsigned long flags; |
| 275 | 206 | |
| 276 | 207 | spin_lock_irqsave(&trans->reg_lock, flags); |
| 277 | − if (likely(iwl_grab_nic_access(trans))) { | |
| 208 | + if (iwl_trans_grab_nic_access(trans, false)) { | |
| 278 | 209 | __iwl_write_prph(trans, ofs, |
| 279 | 210 | (__iwl_read_prph(trans, ofs) & mask) | bits); |
| 280 | − iwl_release_nic_access(trans); | |
| 211 | + iwl_trans_release_nic_access(trans); | |
| 281 | 212 | } |
| 282 | 213 | spin_unlock_irqrestore(&trans->reg_lock, flags); |
| 283 | 214 | } |
| @@ -289,66 +220,11 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) · 5 unmodified lines | ||
| 289 | 220 | u32 val; |
| 290 | 221 | |
| 291 | 222 | spin_lock_irqsave(&trans->reg_lock, flags); |
| 292 | − if (likely(iwl_grab_nic_access(trans))) { | |
| 223 | + if (iwl_trans_grab_nic_access(trans, false)) { | |
| 293 | 224 | val = __iwl_read_prph(trans, ofs); |
| 294 | 225 | __iwl_write_prph(trans, ofs, (val & ~mask)); |
| 295 | − iwl_release_nic_access(trans); | |
| 226 | + iwl_trans_release_nic_access(trans); | |
| 296 | 227 | } |
| 297 | 228 | spin_unlock_irqrestore(&trans->reg_lock, flags); |
| 298 | 229 | } |
| 299 | 230 | EXPORT_SYMBOL_GPL(iwl_clear_bits_prph); |
| 300 | − | |
| 301 | −void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr, | |
| 302 | − void *buf, int dwords) | |
| 303 | −{ | |
| 304 | − unsigned long flags; | |
| 305 | − int offs; | |
| 306 | − u32 *vals = buf; | |
| 307 | − | |
| 308 | − spin_lock_irqsave(&trans->reg_lock, flags); | |
| 309 | − if (likely(iwl_grab_nic_access(trans))) { | |
| 310 | − iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); | |
| 311 | − for (offs = 0; offs < dwords; offs++) | |
| 312 | − vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); | |
| 313 | − iwl_release_nic_access(trans); | |
| 314 | − } | |
| 315 | − spin_unlock_irqrestore(&trans->reg_lock, flags); | |
| 316 | −} | |
| 317 | −EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_dwords); | |
| 318 | − | |
| 319 | −u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr) | |
| 320 | −{ | |
| 321 | − u32 value; | |
| 322 | − | |
| 323 | − _iwl_read_targ_mem_dwords(trans, addr, &value, 1); | |
| 324 | − | |
| 325 | − return value; | |
| 326 | −} | |
| 327 | −EXPORT_SYMBOL_GPL(iwl_read_targ_mem); | |
| 328 | − | |
| 329 | −int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr, | |
| 330 | − const void *buf, int dwords) | |
| 331 | −{ | |
| 332 | − unsigned long flags; | |
| 333 | − int offs, result = 0; | |
| 334 | − const u32 *vals = buf; | |
| 335 | − | |
| 336 | − spin_lock_irqsave(&trans->reg_lock, flags); | |
| 337 | − if (likely(iwl_grab_nic_access(trans))) { | |
| 338 | − iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); | |
| 339 | − for (offs = 0; offs < dwords; offs++) | |
| 340 | − iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]); | |
| 341 | − iwl_release_nic_access(trans); | |
| 342 | − } else | |
| 343 | − result = -EBUSY; | |
| 344 | − spin_unlock_irqrestore(&trans->reg_lock, flags); | |
| 345 | − | |
| 346 | − return result; | |
| 347 | −} | |
| 348 | −EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_dwords); | |
| 349 | − | |
| 350 | −int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val) | |
| 351 | −{ | |
| 352 | − return _iwl_write_targ_mem_dwords(trans, addr, &val, 1); | |
| 353 | −} | |
| 354 | −EXPORT_SYMBOL_GPL(iwl_write_targ_mem); | |
| @@ -53,6 +53,8 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs) · 52 unmodified lines | ||
| 53 | 53 | |
| 54 | 54 | void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask); |
| 55 | 55 | void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask); |
| 56 | +void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask); | |
| 57 | +void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask); | |
| 56 | 58 | |
| 57 | 59 | void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value); |
| 58 | 60 | |
| @@ -61,10 +63,6 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr, · 2 unmodified lines | ||
| 61 | 63 | int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, |
| 62 | 64 | int timeout); |
| 63 | 65 | |
| 64 | −int iwl_grab_nic_access_silent(struct iwl_trans *trans); | |
| 65 | −bool iwl_grab_nic_access(struct iwl_trans *trans); | |
| 66 | −void iwl_release_nic_access(struct iwl_trans *trans); | |
| 67 | − | |
| 68 | 66 | u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg); |
| 69 | 67 | void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); |
| 70 | 68 | |
| @@ -76,19 +74,4 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, · 5 unmodified lines | ||
| 76 | 74 | u32 bits, u32 mask); |
| 77 | 75 | void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); |
| 78 | 76 | |
| 79 | −void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr, | |
| 80 | − void *buf, int dwords); | |
| 81 | − | |
| 82 | −#define iwl_read_targ_mem_bytes(trans, addr, buf, bufsize) \ | |
| 83 | − do { \ | |
| 84 | − BUILD_BUG_ON((bufsize) % sizeof(u32)); \ | |
| 85 | − _iwl_read_targ_mem_dwords(trans, addr, buf, \ | |
| 86 | − (bufsize) / sizeof(u32));\ | |
| 87 | − } while (0) | |
| 88 | − | |
| 89 | −int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr, | |
| 90 | − const void *buf, int dwords); | |
| 91 | − | |
| 92 | −u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr); | |
| 93 | −int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val); | |
| 94 | 77 | #endif |
| @@ -467,18 +467,20 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size) · 466 unmodified lines | ||
| 467 | 467 | if (IWL_ABS_PRPH_START <= addr && |
| 468 | 468 | addr < IWL_ABS_PRPH_START + PRPH_END) { |
| 469 | 469 | spin_lock_irqsave(&trans->reg_lock, flags); |
| 470 | − iwl_grab_nic_access(trans); | |
| 470 | + if (!iwl_trans_grab_nic_access(trans, false)) { | |
| 471 | + spin_unlock_irqrestore(&trans->reg_lock, flags); | |
| 472 | + return -EIO; | |
| 473 | + } | |
| 471 | 474 | iwl_write32(trans, HBUS_TARG_PRPH_RADDR, |
| 472 | 475 | addr | (3 << 24)); |
| 473 | 476 | for (i = 0; i < size; i += 4) |
| 474 | 477 | *(u32 *)(tst->mem.addr + i) = |
| 475 | 478 | iwl_read32(trans, HBUS_TARG_PRPH_RDAT); |
| 476 | − iwl_release_nic_access(trans); | |
| 479 | + iwl_trans_release_nic_access(trans); | |
| 477 | 480 | spin_unlock_irqrestore(&trans->reg_lock, flags); |
| 478 | 481 | } else { /* target memory (SRAM) */ |
| 479 | − _iwl_read_targ_mem_dwords(trans, addr, | |
| 480 | − tst->mem.addr, | |
| 481 | − tst->mem.size / 4); | |
| 482 | + iwl_trans_read_mem(trans, addr, tst->mem.addr, | |
| 483 | + tst->mem.size / 4); | |
| 482 | 484 | } |
| 483 | 485 | |
| 484 | 486 | tst->mem.nchunks = |
| @@ -501,28 +503,31 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr, · 16 unmodified lines | ||
| 501 | 503 | |
| 502 | 504 | if (IWL_ABS_PRPH_START <= addr && |
| 503 | 505 | addr < IWL_ABS_PRPH_START + PRPH_END) { |
| 504 | − /* Periphery writes can be 1-3 bytes long, or DWORDs */ | |
| 505 | − if (size < 4) { | |
| 506 | − memcpy(&val, buf, size); | |
| 507 | − spin_lock_irqsave(&trans->reg_lock, flags); | |
| 508 | − iwl_grab_nic_access(trans); | |
| 509 | − iwl_write32(trans, HBUS_TARG_PRPH_WADDR, | |
| 510 | − (addr & 0x0000FFFF) | | |
| 511 | − ((size - 1) << 24)); | |
| 512 | − iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); | |
| 513 | − iwl_release_nic_access(trans); | |
| 514 | − /* needed after consecutive writes w/o read */ | |
| 515 | − mmiowb(); | |
| 506 | + /* Periphery writes can be 1-3 bytes long, or DWORDs */ | |
| 507 | + if (size < 4) { | |
| 508 | + memcpy(&val, buf, size); | |
| 509 | + spin_lock_irqsave(&trans->reg_lock, flags); | |
| 510 | + if (!iwl_trans_grab_nic_access(trans, false)) { | |
| 516 | 511 | spin_unlock_irqrestore(&trans->reg_lock, flags); |
| 517 | − } else { | |
| 518 | − if (size % 4) | |
| 519 | − return -EINVAL; | |
| 520 | − for (i = 0; i < size; i += 4) | |
| 521 | − iwl_write_prph(trans, addr+i, | |
| 522 | − *(u32 *)(buf+i)); | |
| 512 | + return -EIO; | |
| 523 | 513 | } |
| 514 | + iwl_write32(trans, HBUS_TARG_PRPH_WADDR, | |
| 515 | + (addr & 0x0000FFFF) | | |
| 516 | + ((size - 1) << 24)); | |
| 517 | + iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); | |
| 518 | + iwl_trans_release_nic_access(trans); | |
| 519 | + /* needed after consecutive writes w/o read */ | |
| 520 | + mmiowb(); | |
| 521 | + spin_unlock_irqrestore(&trans->reg_lock, flags); | |
| 522 | + } else { | |
| 523 | + if (size % 4) | |
| 524 | + return -EINVAL; | |
| 525 | + for (i = 0; i < size; i += 4) | |
| 526 | + iwl_write_prph(trans, addr+i, | |
| 527 | + *(u32 *)(buf+i)); | |
| 528 | + } | |
| 524 | 529 | } else if (iwl_test_valid_hw_addr(tst, addr)) { |
| 525 | − _iwl_write_targ_mem_dwords(trans, addr, buf, size / 4); | |
| 530 | + iwl_trans_write_mem(trans, addr, buf, size / 4); | |
| 526 | 531 | } else { |
| 527 | 532 | return -EINVAL; |
| 528 | 533 | } |
| @@ -307,6 +307,16 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) · 306 unmodified lines | ||
| 307 | 307 | #define IWL_MAX_TID_COUNT 8 |
| 308 | 308 | #define IWL_FRAME_LIMIT 64 |
| 309 | 309 | |
| 310 | +/** | |
| 311 | + * enum iwl_wowlan_status - WoWLAN image/device status | |
| 312 | + * @IWL_D3_STATUS_ALIVE: firmware is still running after resume | |
| 313 | + * @IWL_D3_STATUS_RESET: device was reset while suspended | |
| 314 | + */ | |
| 315 | +enum iwl_d3_status { | |
| 316 | + IWL_D3_STATUS_ALIVE, | |
| 317 | + IWL_D3_STATUS_RESET, | |
| 318 | +}; | |
| 319 | + | |
| 310 | 320 | /** |
| 311 | 321 | * struct iwl_trans_config - transport configuration |
| 312 | 322 | * |
| @@ -321,6 +331,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) · 8 unmodified lines | ||
| 321 | 331 | * @n_no_reclaim_cmds: # of commands in list |
| 322 | 332 | * @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs, |
| 323 | 333 | * if unset 4k will be the RX buffer size |
| 334 | + * @bc_table_dword: set to true if the BC table expects the byte count to be | |
| 335 | + * in DWORD (as opposed to bytes) | |
| 324 | 336 | * @queue_watchdog_timeout: time (in ms) after which queues |
| 325 | 337 | * are considered stuck and will trigger device restart |
| 326 | 338 | * @command_names: array of command names, must be 256 entries |
| @@ -335,6 +347,7 @@ struct iwl_trans_config { · 8 unmodified lines | ||
| 335 | 347 | int n_no_reclaim_cmds; |
| 336 | 348 | |
| 337 | 349 | bool rx_buf_size_8k; |
| 350 | + bool bc_table_dword; | |
| 338 | 351 | unsigned int queue_watchdog_timeout; |
| 339 | 352 | const char **command_names; |
| 340 | 353 | }; |
| @@ -360,9 +373,12 @@ struct iwl_trans; · 19 unmodified lines | ||
| 360 | 373 | * May sleep |
| 361 | 374 | * @stop_device:stops the whole device (embedded CPU put to reset) |
| 362 | 375 | * May sleep |
| 363 | − * @wowlan_suspend: put the device into the correct mode for WoWLAN during | |
| 376 | + * @d3_suspend: put the device into the correct mode for WoWLAN during | |
| 364 | 377 | * suspend. This is optional, if not implemented WoWLAN will not be |
| 365 | 378 | * supported. This callback may sleep. |
| 379 | + * @d3_resume: resume the device after WoWLAN, enabling the opmode to | |
| 380 | + * talk to the WoWLAN image to get its status. This is optional, if not | |
| 381 | + * implemented WoWLAN will not be supported. This callback may sleep. | |
| 366 | 382 | * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted. |
| 367 | 383 | * If RFkill is asserted in the middle of a SYNC host command, it must |
| 368 | 384 | * return -ERFKILL straight away. |
| @@ -387,20 +403,27 @@ struct iwl_trans; · 18 unmodified lines | ||
| 387 | 403 | * @read32: read a u32 register at offset ofs from the BAR |
| 388 | 404 | * @read_prph: read a DWORD from a periphery register |
| 389 | 405 | * @write_prph: write a DWORD to a periphery register |
| 406 | + * @read_mem: read device's SRAM in DWORD | |
| 407 | + * @write_mem: write device's SRAM in DWORD. If %buf is %NULL, then the memory | |
| 408 | + * will be zeroed. | |
| 390 | 409 | * @configure: configure parameters required by the transport layer from |
| 391 | 410 | * the op_mode. May be called several times before start_fw, can't be |
| 392 | 411 | * called after that. |
| 393 | 412 | * @set_pmi: set the power pmi state |
| 413 | + * @grab_nic_access: wake the NIC to be able to access non-HBUS regs | |
| 414 | + * @release_nic_access: let the NIC go to sleep | |
| 394 | 415 | */ |
| 395 | 416 | struct iwl_trans_ops { |
| 396 | 417 | |
| 397 | 418 | int (*start_hw)(struct iwl_trans *iwl_trans); |
| 398 | 419 | void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving); |
| 399 | − int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw); | |
| 420 | + int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw, | |
| 421 | + bool run_in_rfkill); | |
| 400 | 422 | void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); |
| 401 | 423 | void (*stop_device)(struct iwl_trans *trans); |
| 402 | 424 | |
| 403 | − void (*wowlan_suspend)(struct iwl_trans *trans); | |
| 425 | + void (*d3_suspend)(struct iwl_trans *trans); | |
| 426 | + int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status); | |
| 404 | 427 | |
| 405 | 428 | int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); |
| 406 | 429 | |
| @@ -424,9 +447,15 @@ struct iwl_trans_ops { · 17 unmodified lines | ||
| 424 | 447 | u32 (*read32)(struct iwl_trans *trans, u32 ofs); |
| 425 | 448 | u32 (*read_prph)(struct iwl_trans *trans, u32 ofs); |
| 426 | 449 | void (*write_prph)(struct iwl_trans *trans, u32 ofs, u32 val); |
| 450 | + int (*read_mem)(struct iwl_trans *trans, u32 addr, | |
| 451 | + void *buf, int dwords); | |
| 452 | + int (*write_mem)(struct iwl_trans *trans, u32 addr, | |
| 453 | + void *buf, int dwords); | |
| 427 | 454 | void (*configure)(struct iwl_trans *trans, |
| 428 | 455 | const struct iwl_trans_config *trans_cfg); |
| 429 | 456 | void (*set_pmi)(struct iwl_trans *trans, bool state); |
| 457 | + bool (*grab_nic_access)(struct iwl_trans *trans, bool silent); | |
| 458 | + void (*release_nic_access)(struct iwl_trans *trans); | |
| 430 | 459 | }; |
| 431 | 460 | |
| 432 | 461 | /** |
| @@ -528,13 +557,14 @@ static inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr) · 95 unmodified lines | ||
| 528 | 557 | } |
| 529 | 558 | |
| 530 | 559 | static inline int iwl_trans_start_fw(struct iwl_trans *trans, |
| 531 | − const struct fw_img *fw) | |
| 560 | + const struct fw_img *fw, | |
| 561 | + bool run_in_rfkill) | |
| 532 | 562 | { |
| 533 | 563 | might_sleep(); |
| 534 | 564 | |
| 535 | 565 | WARN_ON_ONCE(!trans->rx_mpdu_cmd); |
| 536 | 566 | |
| 537 | − return trans->ops->start_fw(trans, fw); | |
| 567 | + return trans->ops->start_fw(trans, fw, run_in_rfkill); | |
| 538 | 568 | } |
| 539 | 569 | |
| 540 | 570 | static inline void iwl_trans_stop_device(struct iwl_trans *trans) |
| @@ -546,10 +576,17 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans) · 5 unmodified lines | ||
| 546 | 576 | trans->state = IWL_TRANS_NO_FW; |
| 547 | 577 | } |
| 548 | 578 | |
| 549 | −static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans) | |
| 579 | +static inline void iwl_trans_d3_suspend(struct iwl_trans *trans) | |
| 580 | +{ | |
| 581 | + might_sleep(); | |
| 582 | + trans->ops->d3_suspend(trans); | |
| 583 | +} | |
| 584 | + | |
| 585 | +static inline int iwl_trans_d3_resume(struct iwl_trans *trans, | |
| 586 | + enum iwl_d3_status *status) | |
| 550 | 587 | { |
| 551 | 588 | might_sleep(); |
| 552 | − trans->ops->wowlan_suspend(trans); | |
| 589 | + return trans->ops->d3_resume(trans, status); | |
| 553 | 590 | } |
| 554 | 591 | |
| 555 | 592 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, |
| @@ -636,7 +673,7 @@ static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) · 80 unmodified lines | ||
| 636 | 673 | } |
| 637 | 674 | |
| 638 | 675 | static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, |
| 639 | − struct dentry *dir) | |
| 676 | + struct dentry *dir) | |
| 640 | 677 | { |
| 641 | 678 | return trans->ops->dbgfs_register(trans, dir); |
| 642 | 679 | } |
| @@ -679,11 +716,57 @@ static inline void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, · 36 unmodified lines | ||
| 679 | 716 | return trans->ops->write_prph(trans, ofs, val); |
| 680 | 717 | } |
| 681 | 718 | |
| 719 | +static inline int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr, | |
| 720 | + void *buf, int dwords) | |
| 721 | +{ | |
| 722 | + return trans->ops->read_mem(trans, addr, buf, dwords); | |
| 723 | +} | |
| 724 | + | |
| 725 | +#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \ | |
| 726 | + do { \ | |
| 727 | + if (__builtin_constant_p(bufsize)) \ | |
| 728 | + BUILD_BUG_ON((bufsize) % sizeof(u32)); \ | |
| 729 | + iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\ | |
| 730 | + } while (0) | |
| 731 | + | |
| 732 | +static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr) | |
| 733 | +{ | |
| 734 | + u32 value; | |
| 735 | + | |
| 736 | + if (WARN_ON(iwl_trans_read_mem(trans, addr, &value, 1))) | |
| 737 | + return 0xa5a5a5a5; | |
| 738 | + | |
| 739 | + return value; | |
| 740 | +} | |
| 741 | + | |
| 742 | +static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, | |
| 743 | + void *buf, int dwords) | |
| 744 | +{ | |
| 745 | + return trans->ops->write_mem(trans, addr, buf, dwords); | |
| 746 | +} | |
| 747 | + | |
| 748 | +static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr, | |
| 749 | + u32 val) | |
| 750 | +{ | |
| 751 | + return iwl_trans_write_mem(trans, addr, &val, 1); | |
| 752 | +} | |
| 753 | + | |
| 682 | 754 | static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) |
| 683 | 755 | { |
| 684 | 756 | trans->ops->set_pmi(trans, state); |
| 685 | 757 | } |
| 686 | 758 | |
| 759 | +#define iwl_trans_grab_nic_access(trans, silent) \ | |
| 760 | + __cond_lock(nic_access, \ | |
| 761 | + likely((trans)->ops->grab_nic_access(trans, silent))) | |
| 762 | + | |
| 763 | +static inline void __releases(nic_access) | |
| 764 | +iwl_trans_release_nic_access(struct iwl_trans *trans) | |
| 765 | +{ | |
| 766 | + trans->ops->release_nic_access(trans); | |
| 767 | + __release(nic_access); | |
| 768 | +} | |
| 769 | + | |
| 687 | 770 | /***************************************************** |
| 688 | 771 | * driver (transport) register/unregister functions |
| 689 | 772 | ******************************************************/ |
| @@ -222,8 +222,6 @@ struct iwl_txq { · 221 unmodified lines | ||
| 222 | 222 | * @rx_replenish: work that will be called when buffers need to be allocated |
| 223 | 223 | * @drv - pointer to iwl_drv |
| 224 | 224 | * @trans: pointer to the generic transport area |
| 225 | − * @irq - the irq number for the device | |
| 226 | − * @irq_requested: true when the irq has been requested | |
| 227 | 225 | * @scd_base_addr: scheduler sram base address in SRAM |
| 228 | 226 | * @scd_bc_tbls: pointer to the byte count table of the scheduler |
| 229 | 227 | * @kw: keep warm address |
| @@ -234,6 +232,7 @@ struct iwl_txq { · 4 unmodified lines | ||
| 234 | 232 | * @status - transport specific status flags |
| 235 | 233 | * @cmd_queue - command queue number |
| 236 | 234 | * @rx_buf_size_8k: 8 kB RX buffer size |
| 235 | + * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) | |
| 237 | 236 | * @rx_page_order: page order for receive buffer size |
| 238 | 237 | * @wd_timeout: queue watchdog timeout (jiffies) |
| 239 | 238 | */ |
| @@ -249,11 +248,9 @@ struct iwl_trans_pcie { · 9 unmodified lines | ||
| 249 | 248 | int ict_index; |
| 250 | 249 | u32 inta; |
| 251 | 250 | bool use_ict; |
| 252 | − bool irq_requested; | |
| 253 | 251 | struct tasklet_struct irq_tasklet; |
| 254 | 252 | struct isr_statistics isr_stats; |
| 255 | 253 | |
| 256 | − unsigned int irq; | |
| 257 | 254 | spinlock_t irq_lock; |
| 258 | 255 | u32 inta_mask; |
| 259 | 256 | u32 scd_base_addr; |
| @@ -279,6 +276,7 @@ struct iwl_trans_pcie { · 19 unmodified lines | ||
| 279 | 276 | u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; |
| 280 | 277 | |
| 281 | 278 | bool rx_buf_size_8k; |
| 279 | + bool bc_table_dword; | |
| 282 | 280 | u32 rx_page_order; |
| 283 | 281 | |
| 284 | 282 | const char **command_names; |
| @@ -359,6 +357,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, · 74 unmodified lines | ||
| 359 | 357 | struct iwl_rx_cmd_buffer *rxb, int handler_status); |
| 360 | 358 | void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, |
| 361 | 359 | struct sk_buff_head *skbs); |
| 360 | +void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); | |
| 361 | + | |
| 362 | 362 | /***************************************************** |
| 363 | 363 | * Error handling |
| 364 | 364 | ******************************************************/ |
| @@ -436,7 +436,7 @@ static int iwl_pcie_rx_alloc(struct iwl_trans *trans) · 435 unmodified lines | ||
| 436 | 436 | err_rb_stts: |
| 437 | 437 | dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, |
| 438 | 438 | rxq->bd, rxq->bd_dma); |
| 439 | − memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); | |
| 439 | + rxq->bd_dma = 0; | |
| 440 | 440 | rxq->bd = NULL; |
| 441 | 441 | err_bd: |
| 442 | 442 | return -ENOMEM; |
| @@ -455,6 +455,10 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) · 12 unmodified lines | ||
| 455 | 455 | |
| 456 | 456 | /* Stop Rx DMA */ |
| 457 | 457 | iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); |
| 458 | + /* reset and flush pointers */ | |
| 459 | + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0); | |
| 460 | + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0); | |
| 461 | + iwl_write_direct32(trans, FH_RSCSR_CHNL0_RDPTR, 0); | |
| 458 | 462 | |
| 459 | 463 | /* Reset driver's Rx queue write index */ |
| 460 | 464 | iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); |
| @@ -491,7 +495,6 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) · 30 unmodified lines | ||
| 491 | 495 | { |
| 492 | 496 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 493 | 497 | struct iwl_rxq *rxq = &trans_pcie->rxq; |
| 494 | − | |
| 495 | 498 | int i, err; |
| 496 | 499 | unsigned long flags; |
| 497 | 500 | |
| @@ -518,6 +521,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) · 20 unmodified lines | ||
| 518 | 521 | rxq->read = rxq->write = 0; |
| 519 | 522 | rxq->write_actual = 0; |
| 520 | 523 | rxq->free_count = 0; |
| 524 | + memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); | |
| 521 | 525 | spin_unlock_irqrestore(&rxq->lock, flags); |
| 522 | 526 | |
| 523 | 527 | iwl_pcie_rx_replenish(trans); |
| @@ -545,13 +549,15 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) · 21 unmodified lines | ||
| 545 | 549 | return; |
| 546 | 550 | } |
| 547 | 551 | |
| 552 | + cancel_work_sync(&trans_pcie->rx_replenish); | |
| 553 | + | |
| 548 | 554 | spin_lock_irqsave(&rxq->lock, flags); |
| 549 | 555 | iwl_pcie_rxq_free_rbs(trans); |
| 550 | 556 | spin_unlock_irqrestore(&rxq->lock, flags); |
| 551 | 557 | |
| 552 | 558 | dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE, |
| 553 | 559 | rxq->bd, rxq->bd_dma); |
| 554 | − memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); | |
| 560 | + rxq->bd_dma = 0; | |
| 555 | 561 | rxq->bd = NULL; |
| 556 | 562 | |
| 557 | 563 | if (rxq->rb_stts) |
| @@ -560,7 +566,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) · 2 unmodified lines | ||
| 560 | 566 | rxq->rb_stts, rxq->rb_stts_dma); |
| 561 | 567 | else |
| 562 | 568 | IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n"); |
| 563 | − memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma)); | |
| 569 | + rxq->rb_stts_dma = 0; | |
| 564 | 570 | rxq->rb_stts = NULL; |
| 565 | 571 | } |
| 566 | 572 | |
| @@ -1166,6 +1172,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) · 599 unmodified lines | ||
| 1166 | 1172 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && |
| 1167 | 1173 | !trans_pcie->inta) |
| 1168 | 1174 | iwl_enable_interrupts(trans); |
| 1175 | + return IRQ_HANDLED; | |
| 1169 | 1176 | |
| 1170 | 1177 | none: |
| 1171 | 1178 | /* re-enable interrupts here since we don't have anything to service. */ |
| @@ -75,21 +75,16 @@ · 74 unmodified lines | ||
| 75 | 75 | #include "iwl-agn-hw.h" |
| 76 | 76 | #include "internal.h" |
| 77 | 77 | |
| 78 | −static void iwl_pcie_set_pwr_vmain(struct iwl_trans *trans) | |
| 78 | +static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) | |
| 79 | 79 | { |
| 80 | −/* | |
| 81 | − * (for documentation purposes) | |
| 82 | − * to set power to V_AUX, do: | |
| 83 | − | |
| 84 | − if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) | |
| 85 | − iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, | |
| 86 | − APMG_PS_CTRL_VAL_PWR_SRC_VAUX, | |
| 87 | − ~APMG_PS_CTRL_MSK_PWR_SRC); | |
| 88 | − */ | |
| 89 | − | |
| 90 | − iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, | |
| 91 | − APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, | |
| 92 | − ~APMG_PS_CTRL_MSK_PWR_SRC); | |
| 80 | + if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) | |
| 81 | + iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, | |
| 82 | + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, | |
| 83 | + ~APMG_PS_CTRL_MSK_PWR_SRC); | |
| 84 | + else | |
| 85 | + iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, | |
| 86 | + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, | |
| 87 | + ~APMG_PS_CTRL_MSK_PWR_SRC); | |
| 93 | 88 | } |
| 94 | 89 | |
| 95 | 90 | /* PCI registers */ |
| @@ -259,7 +254,7 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans) · 163 unmodified lines | ||
| 259 | 254 | |
| 260 | 255 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); |
| 261 | 256 | |
| 262 | − iwl_pcie_set_pwr_vmain(trans); | |
| 257 | + iwl_pcie_set_pwr(trans, false); | |
| 263 | 258 | |
| 264 | 259 | iwl_op_mode_nic_config(trans->op_mode); |
| 265 | 260 | |
| @@ -435,7 +430,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, · 169 unmodified lines | ||
| 435 | 430 | } |
| 436 | 431 | |
| 437 | 432 | static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, |
| 438 | − const struct fw_img *fw) | |
| 433 | + const struct fw_img *fw, bool run_in_rfkill) | |
| 439 | 434 | { |
| 440 | 435 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 441 | 436 | int ret; |
| @@ -454,7 +449,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, · 12 unmodified lines | ||
| 454 | 449 | /* If platform's RF_KILL switch is NOT set to KILL */ |
| 455 | 450 | hw_rfkill = iwl_is_rfkill_set(trans); |
| 456 | 451 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); |
| 457 | − if (hw_rfkill) | |
| 452 | + if (hw_rfkill && !run_in_rfkill) | |
| 458 | 453 | return -ERFKILL; |
| 459 | 454 | |
| 460 | 455 | iwl_write32(trans, CSR_INT, 0xFFFFFFFF); |
| @@ -534,12 +529,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) · 73 unmodified lines | ||
| 534 | 529 | |
| 535 | 530 | iwl_enable_rfkill_int(trans); |
| 536 | 531 | |
| 537 | − /* wait to make sure we flush pending tasklet*/ | |
| 538 | − synchronize_irq(trans_pcie->irq); | |
| 539 | − tasklet_kill(&trans_pcie->irq_tasklet); | |
| 540 | − | |
| 541 | − cancel_work_sync(&trans_pcie->rx_replenish); | |
| 542 | − | |
| 543 | 532 | /* stop and reset the on-board processor */ |
| 544 | 533 | iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); |
| 545 | 534 | |
| @@ -551,46 +540,87 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) · 5 unmodified lines | ||
| 551 | 540 | clear_bit(STATUS_RFKILL, &trans_pcie->status); |
| 552 | 541 | } |
| 553 | 542 | |
| 554 | −static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans) | |
| 543 | +static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans) | |
| 555 | 544 | { |
| 556 | 545 | /* let the ucode operate on its own */ |
| 557 | 546 | iwl_write32(trans, CSR_UCODE_DRV_GP1_SET, |
| 558 | 547 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); |
| 559 | 548 | |
| 560 | 549 | iwl_disable_interrupts(trans); |
| 550 | + iwl_pcie_disable_ict(trans); | |
| 551 | + | |
| 561 | 552 | iwl_clear_bit(trans, CSR_GP_CNTRL, |
| 562 | 553 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
| 554 | + iwl_clear_bit(trans, CSR_GP_CNTRL, | |
| 555 | + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | |
| 556 | + | |
| 557 | + /* | |
| 558 | + * reset TX queues -- some of their registers reset during S3 | |
| 559 | + * so if we don't reset everything here the D3 image would try | |
| 560 | + * to execute some invalid memory upon resume | |
| 561 | + */ | |
| 562 | + iwl_trans_pcie_tx_reset(trans); | |
| 563 | + | |
| 564 | + iwl_pcie_set_pwr(trans, true); | |
| 563 | 565 | } |
| 564 | 566 | |
| 565 | −static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) | |
| 567 | +static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, | |
| 568 | + enum iwl_d3_status *status) | |
| 566 | 569 | { |
| 567 | − struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | |
| 568 | − int err; | |
| 569 | − bool hw_rfkill; | |
| 570 | + u32 val; | |
| 571 | + int ret; | |
| 570 | 572 | |
| 571 | − trans_pcie->inta_mask = CSR_INI_SET_MASK; | |
| 573 | + iwl_pcie_set_pwr(trans, false); | |
| 572 | 574 | |
| 573 | − if (!trans_pcie->irq_requested) { | |
| 574 | − tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) | |
| 575 | − iwl_pcie_tasklet, (unsigned long)trans); | |
| 575 | + val = iwl_read32(trans, CSR_RESET); | |
| 576 | + if (val & CSR_RESET_REG_FLAG_NEVO_RESET) { | |
| 577 | + *status = IWL_D3_STATUS_RESET; | |
| 578 | + return 0; | |
| 579 | + } | |
| 576 | 580 | |
| 577 | − iwl_pcie_alloc_ict(trans); | |
| 581 | + /* | |
| 582 | + * Also enables interrupts - none will happen as the device doesn't | |
| 583 | + * know we're waking it up, only when the opmode actually tells it | |
| 584 | + * after this call. | |
| 585 | + */ | |
| 586 | + iwl_pcie_reset_ict(trans); | |
| 578 | 587 | |
| 579 | − err = request_irq(trans_pcie->irq, iwl_pcie_isr_ict, | |
| 580 | − IRQF_SHARED, DRV_NAME, trans); | |
| 581 | − if (err) { | |
| 582 | − IWL_ERR(trans, "Error allocating IRQ %d\n", | |
| 583 | − trans_pcie->irq); | |
| 584 | − goto error; | |
| 585 | − } | |
| 588 | + iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | |
| 589 | + iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | |
| 586 | 590 | |
| 587 | − trans_pcie->irq_requested = true; | |
| 591 | + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | |
| 592 | + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | |
| 593 | + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | |
| 594 | + 25000); | |
| 595 | + if (ret) { | |
| 596 | + IWL_ERR(trans, "Failed to resume the device (mac ready)\n"); | |
| 597 | + return ret; | |
| 588 | 598 | } |
| 589 | 599 | |
| 600 | + iwl_trans_pcie_tx_reset(trans); | |
| 601 | + | |
| 602 | + ret = iwl_pcie_rx_init(trans); | |
| 603 | + if (ret) { | |
| 604 | + IWL_ERR(trans, "Failed to resume the device (RX reset)\n"); | |
| 605 | + return ret; | |
| 606 | + } | |
| 607 | + | |
| 608 | + iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, | |
| 609 | + CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | |
| 610 | + | |
| 611 | + *status = IWL_D3_STATUS_ALIVE; | |
| 612 | + return 0; | |
| 613 | +} | |
| 614 | + | |
| 615 | +static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) | |
| 616 | +{ | |
| 617 | + bool hw_rfkill; | |
| 618 | + int err; | |
| 619 | + | |
| 590 | 620 | err = iwl_pcie_prepare_card_hw(trans); |
| 591 | 621 | if (err) { |
| 592 | 622 | IWL_ERR(trans, "Error while preparing HW: %d\n", err); |
| 593 | − goto err_free_irq; | |
| 623 | + return err; | |
| 594 | 624 | } |
| 595 | 625 | |
| 596 | 626 | iwl_pcie_apm_init(trans); |
| @@ -601,15 +631,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) · 4 unmodified lines | ||
| 601 | 631 | hw_rfkill = iwl_is_rfkill_set(trans); |
| 602 | 632 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); |
| 603 | 633 | |
| 604 | − return err; | |
| 605 | − | |
| 606 | −err_free_irq: | |
| 607 | − trans_pcie->irq_requested = false; | |
| 608 | − free_irq(trans_pcie->irq, trans); | |
| 609 | −error: | |
| 610 | − iwl_pcie_free_ict(trans); | |
| 611 | − tasklet_kill(&trans_pcie->irq_tasklet); | |
| 612 | − return err; | |
| 634 | + return 0; | |
| 613 | 635 | } |
| 614 | 636 | |
| 615 | 637 | static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, |
| @@ -703,19 +725,21 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, · 87 unmodified lines | ||
| 703 | 725 | msecs_to_jiffies(trans_cfg->queue_watchdog_timeout); |
| 704 | 726 | |
| 705 | 727 | trans_pcie->command_names = trans_cfg->command_names; |
| 728 | + trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; | |
| 706 | 729 | } |
| 707 | 730 | |
| 708 | 731 | void iwl_trans_pcie_free(struct iwl_trans *trans) |
| 709 | 732 | { |
| 710 | 733 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 711 | 734 | |
| 735 | + synchronize_irq(trans_pcie->pci_dev->irq); | |
| 736 | + tasklet_kill(&trans_pcie->irq_tasklet); | |
| 737 | + | |
| 712 | 738 | iwl_pcie_tx_free(trans); |
| 713 | 739 | iwl_pcie_rx_free(trans); |
| 714 | 740 | |
| 715 | − if (trans_pcie->irq_requested == true) { | |
| 716 | − free_irq(trans_pcie->irq, trans); | |
| 717 | − iwl_pcie_free_ict(trans); | |
| 718 | − } | |
| 741 | + free_irq(trans_pcie->pci_dev->irq, trans); | |
| 742 | + iwl_pcie_free_ict(trans); | |
| 719 | 743 | |
| 720 | 744 | pci_disable_msi(trans_pcie->pci_dev); |
| 721 | 745 | iounmap(trans_pcie->hw_base); |
| @@ -751,13 +775,112 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) · 29 unmodified lines | ||
| 751 | 775 | hw_rfkill = iwl_is_rfkill_set(trans); |
| 752 | 776 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); |
| 753 | 777 | |
| 754 | − if (!hw_rfkill) | |
| 755 | − iwl_enable_interrupts(trans); | |
| 756 | − | |
| 757 | 778 | return 0; |
| 758 | 779 | } |
| 759 | 780 | #endif /* CONFIG_PM_SLEEP */ |
| 760 | 781 | |
| 782 | +static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) | |
| 783 | +{ | |
| 784 | + int ret; | |
| 785 | + | |
| 786 | + lockdep_assert_held(&trans->reg_lock); | |
| 787 | + | |
| 788 | + /* this bit wakes up the NIC */ | |
| 789 | + __iwl_set_bit(trans, CSR_GP_CNTRL, | |
| 790 | + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | |
| 791 | + | |
| 792 | + /* | |
| 793 | + * These bits say the device is running, and should keep running for | |
| 794 | + * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), | |
| 795 | + * but they do not indicate that embedded SRAM is restored yet; | |
| 796 | + * 3945 and 4965 have volatile SRAM, and must save/restore contents | |
| 797 | + * to/from host DRAM when sleeping/waking for power-saving. | |
| 798 | + * Each direction takes approximately 1/4 millisecond; with this | |
| 799 | + * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a | |
| 800 | + * series of register accesses are expected (e.g. reading Event Log), | |
| 801 | + * to keep device from sleeping. | |
| 802 | + * | |
| 803 | + * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that | |
| 804 | + * SRAM is okay/restored. We don't check that here because this call | |
| 805 | + * is just for hardware register access; but GP1 MAC_SLEEP check is a | |
| 806 | + * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). | |
| 807 | + * | |
| 808 | + * 5000 series and later (including 1000 series) have non-volatile SRAM, | |
| 809 | + * and do not save/restore SRAM when power cycling. | |
| 810 | + */ | |
| 811 | + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | |
| 812 | + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, | |
| 813 | + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | | |
| 814 | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); | |
| 815 | + if (unlikely(ret < 0)) { | |
| 816 | + iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); | |
| 817 | + if (!silent) { | |
| 818 | + u32 val = iwl_read32(trans, CSR_GP_CNTRL); | |
| 819 | + WARN_ONCE(1, | |
| 820 | + "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n", | |
| 821 | + val); | |
| 822 | + return false; | |
| 823 | + } | |
| 824 | + } | |
| 825 | + | |
| 826 | + return true; | |
| 827 | +} | |
| 828 | + | |
| 829 | +static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans) | |
| 830 | +{ | |
| 831 | + lockdep_assert_held(&trans->reg_lock); | |
| 832 | + __iwl_clear_bit(trans, CSR_GP_CNTRL, | |
| 833 | + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | |
| 834 | + /* | |
| 835 | + * Above we read the CSR_GP_CNTRL register, which will flush | |
| 836 | + * any previous writes, but we need the write that clears the | |
| 837 | + * MAC_ACCESS_REQ bit to be performed before any other writes | |
| 838 | + * scheduled on different CPUs (after we drop reg_lock). | |
| 839 | + */ | |
| 840 | + mmiowb(); | |
| 841 | +} | |
| 842 | + | |
| 843 | +static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, | |
| 844 | + void *buf, int dwords) | |
| 845 | +{ | |
| 846 | + unsigned long flags; | |
| 847 | + int offs, ret = 0; | |
| 848 | + u32 *vals = buf; | |
| 849 | + | |
| 850 | + spin_lock_irqsave(&trans->reg_lock, flags); | |
| 851 | + if (iwl_trans_grab_nic_access(trans, false)) { | |
| 852 | + iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); | |
| 853 | + for (offs = 0; offs < dwords; offs++) | |
| 854 | + vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); | |
| 855 | + iwl_trans_release_nic_access(trans); | |
| 856 | + } else { | |
| 857 | + ret = -EBUSY; | |
| 858 | + } | |
| 859 | + spin_unlock_irqrestore(&trans->reg_lock, flags); | |
| 860 | + return ret; | |
| 861 | +} | |
| 862 | + | |
| 863 | +static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, | |
| 864 | + void *buf, int dwords) | |
| 865 | +{ | |
| 866 | + unsigned long flags; | |
| 867 | + int offs, ret = 0; | |
| 868 | + u32 *vals = buf; | |
| 869 | + | |
| 870 | + spin_lock_irqsave(&trans->reg_lock, flags); | |
| 871 | + if (iwl_trans_grab_nic_access(trans, false)) { | |
| 872 | + iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); | |
| 873 | + for (offs = 0; offs < dwords; offs++) | |
| 874 | + iwl_write32(trans, HBUS_TARG_MEM_WDAT, | |
| 875 | + vals ? vals[offs] : 0); | |
| 876 | + iwl_trans_release_nic_access(trans); | |
| 877 | + } else { | |
| 878 | + ret = -EBUSY; | |
| 879 | + } | |
| 880 | + spin_unlock_irqrestore(&trans->reg_lock, flags); | |
| 881 | + return ret; | |
| 882 | +} | |
| 883 | + | |
| 761 | 884 | #define IWL_FLUSH_WAIT_MS 2000 |
| 762 | 885 | |
| 763 | 886 | static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) |
| @@ -767,6 +890,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) · 3 unmodified lines | ||
| 767 | 890 | struct iwl_queue *q; |
| 768 | 891 | int cnt; |
| 769 | 892 | unsigned long now = jiffies; |
| 893 | + u32 scd_sram_addr; | |
| 894 | + u8 buf[16]; | |
| 770 | 895 | int ret = 0; |
| 771 | 896 | |
| 772 | 897 | /* waiting for all the tx frames complete might take a while */ |
| @@ -780,11 +905,50 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) · 7 unmodified lines | ||
| 780 | 905 | msleep(1); |
| 781 | 906 | |
| 782 | 907 | if (q->read_ptr != q->write_ptr) { |
| 783 | − IWL_ERR(trans, "fail to flush all tx fifo queues\n"); | |
| 908 | + IWL_ERR(trans, | |
| 909 | + "fail to flush all tx fifo queues Q %d\n", cnt); | |
| 784 | 910 | ret = -ETIMEDOUT; |
| 785 | 911 | break; |
| 786 | 912 | } |
| 787 | 913 | } |
| 914 | + | |
| 915 | + if (!ret) | |
| 916 | + return 0; | |
| 917 | + | |
| 918 | + IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", | |
| 919 | + txq->q.read_ptr, txq->q.write_ptr); | |
| 920 | + | |
| 921 | + scd_sram_addr = trans_pcie->scd_base_addr + | |
| 922 | + SCD_TX_STTS_QUEUE_OFFSET(txq->q.id); | |
| 923 | + iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); | |
| 924 | + | |
| 925 | + iwl_print_hex_error(trans, buf, sizeof(buf)); | |
| 926 | + | |
| 927 | + for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++) | |
| 928 | + IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt, | |
| 929 | + iwl_read_direct32(trans, FH_TX_TRB_REG(cnt))); | |
| 930 | + | |
| 931 | + for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { | |
| 932 | + u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt)); | |
| 933 | + u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; | |
| 934 | + bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); | |
| 935 | + u32 tbl_dw = | |
| 936 | + iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr + | |
| 937 | + SCD_TRANS_TBL_OFFSET_QUEUE(cnt)); | |
| 938 | + | |
| 939 | + if (cnt & 0x1) | |
| 940 | + tbl_dw = (tbl_dw & 0xFFFF0000) >> 16; | |
| 941 | + else | |
| 942 | + tbl_dw = tbl_dw & 0x0000FFFF; | |
| 943 | + | |
| 944 | + IWL_ERR(trans, | |
| 945 | + "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n", | |
| 946 | + cnt, active ? "" : "in", fifo, tbl_dw, | |
| 947 | + iwl_read_prph(trans, | |
| 948 | + SCD_QUEUE_RDPTR(cnt)) & (txq->q.n_bd - 1), | |
| 949 | + iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt))); | |
| 950 | + } | |
| 951 | + | |
| 788 | 952 | return ret; |
| 789 | 953 | } |
| 790 | 954 | |
| @@ -1212,7 +1376,8 @@ static const struct iwl_trans_ops trans_ops_pcie = { · 421 unmodified lines | ||
| 1212 | 1376 | .start_fw = iwl_trans_pcie_start_fw, |
| 1213 | 1377 | .stop_device = iwl_trans_pcie_stop_device, |
| 1214 | 1378 | |
| 1215 | − .wowlan_suspend = iwl_trans_pcie_wowlan_suspend, | |
| 1379 | + .d3_suspend = iwl_trans_pcie_d3_suspend, | |
| 1380 | + .d3_resume = iwl_trans_pcie_d3_resume, | |
| 1216 | 1381 | |
| 1217 | 1382 | .send_cmd = iwl_trans_pcie_send_hcmd, |
| 1218 | 1383 | |
| @@ -1235,8 +1400,12 @@ static const struct iwl_trans_ops trans_ops_pcie = { · 16 unmodified lines | ||
| 1235 | 1400 | .read32 = iwl_trans_pcie_read32, |
| 1236 | 1401 | .read_prph = iwl_trans_pcie_read_prph, |
| 1237 | 1402 | .write_prph = iwl_trans_pcie_write_prph, |
| 1403 | + .read_mem = iwl_trans_pcie_read_mem, | |
| 1404 | + .write_mem = iwl_trans_pcie_write_mem, | |
| 1238 | 1405 | .configure = iwl_trans_pcie_configure, |
| 1239 | 1406 | .set_pmi = iwl_trans_pcie_set_pmi, |
| 1407 | + .grab_nic_access = iwl_trans_pcie_grab_nic_access, | |
| 1408 | + .release_nic_access = iwl_trans_pcie_release_nic_access | |
| 1240 | 1409 | }; |
| 1241 | 1410 | |
| 1242 | 1411 | struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, |
| @@ -1318,7 +1487,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, · 75 unmodified lines | ||
| 1318 | 1487 | } |
| 1319 | 1488 | |
| 1320 | 1489 | trans->dev = &pdev->dev; |
| 1321 | − trans_pcie->irq = pdev->irq; | |
| 1322 | 1490 | trans_pcie->pci_dev = pdev; |
| 1323 | 1491 | trans->hw_rev = iwl_read32(trans, CSR_HW_REV); |
| 1324 | 1492 | trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; |
| @@ -1344,8 +1512,27 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, · 19 unmodified lines | ||
| 1344 | 1512 | if (!trans->dev_cmd_pool) |
| 1345 | 1513 | goto out_pci_disable_msi; |
| 1346 | 1514 | |
| 1515 | + trans_pcie->inta_mask = CSR_INI_SET_MASK; | |
| 1516 | + | |
| 1517 | + tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) | |
| 1518 | + iwl_pcie_tasklet, (unsigned long)trans); | |
| 1519 | + | |
| 1520 | + if (iwl_pcie_alloc_ict(trans)) | |
| 1521 | + goto out_free_cmd_pool; | |
| 1522 | + | |
| 1523 | + err = request_irq(pdev->irq, iwl_pcie_isr_ict, | |
| 1524 | + IRQF_SHARED, DRV_NAME, trans); | |
| 1525 | + if (err) { | |
| 1526 | + IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); | |
| 1527 | + goto out_free_ict; | |
| 1528 | + } | |
| 1529 | + | |
| 1347 | 1530 | return trans; |
| 1348 | 1531 | |
| 1532 | +out_free_ict: | |
| 1533 | + iwl_pcie_free_ict(trans); | |
| 1534 | +out_free_cmd_pool: | |
| 1535 | + kmem_cache_destroy(trans->dev_cmd_pool); | |
| 1349 | 1536 | out_pci_disable_msi: |
| 1350 | 1537 | pci_disable_msi(pdev); |
| 1351 | 1538 | out_pci_release_regions: |
| @@ -160,7 +160,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) · 159 unmodified lines | ||
| 160 | 160 | IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", |
| 161 | 161 | txq->q.read_ptr, txq->q.write_ptr); |
| 162 | 162 | |
| 163 | − iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); | |
| 163 | + iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); | |
| 164 | 164 | |
| 165 | 165 | iwl_print_hex_error(trans, buf, sizeof(buf)); |
| 166 | 166 | |
| @@ -173,9 +173,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) · 6 unmodified lines | ||
| 173 | 173 | u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; |
| 174 | 174 | bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); |
| 175 | 175 | u32 tbl_dw = |
| 176 | − iwl_read_targ_mem(trans, | |
| 177 | − trans_pcie->scd_base_addr + | |
| 178 | − SCD_TRANS_TBL_OFFSET_QUEUE(i)); | |
| 176 | + iwl_trans_read_mem32(trans, | |
| 177 | + trans_pcie->scd_base_addr + | |
| 178 | + SCD_TRANS_TBL_OFFSET_QUEUE(i)); | |
| 179 | 179 | |
| 180 | 180 | if (i & 0x1) |
| 181 | 181 | tbl_dw = (tbl_dw & 0xFFFF0000) >> 16; |
| @@ -237,7 +237,10 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans, · 55 unmodified lines | ||
| 237 | 237 | break; |
| 238 | 238 | } |
| 239 | 239 | |
| 240 | − bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12)); | |
| 240 | + if (trans_pcie->bc_table_dword) | |
| 241 | + len = DIV_ROUND_UP(len, 4); | |
| 242 | + | |
| 243 | + bc_ent = cpu_to_le16(len | (sta_id << 12)); | |
| 241 | 244 | |
| 242 | 245 | scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; |
| 243 | 246 | |
| @@ -306,6 +309,9 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) · 62 unmodified lines | ||
| 306 | 309 | return; |
| 307 | 310 | } |
| 308 | 311 | |
| 312 | + IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, | |
| 313 | + txq->q.write_ptr); | |
| 314 | + | |
| 309 | 315 | iwl_write_direct32(trans, HBUS_TARG_WRPTR, |
| 310 | 316 | txq->q.write_ptr | (txq_id << 8)); |
| 311 | 317 | |
| @@ -612,7 +618,7 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) · 300 unmodified lines | ||
| 612 | 618 | if (txq->q.n_bd) { |
| 613 | 619 | dma_free_coherent(dev, sizeof(struct iwl_tfd) * |
| 614 | 620 | txq->q.n_bd, txq->tfds, txq->q.dma_addr); |
| 615 | − memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr)); | |
| 621 | + txq->q.dma_addr = 0; | |
| 616 | 622 | } |
| 617 | 623 | |
| 618 | 624 | kfree(txq->entries); |
| @@ -638,9 +644,11 @@ static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask) · 19 unmodified lines | ||
| 638 | 644 | void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) |
| 639 | 645 | { |
| 640 | 646 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 641 | − u32 a; | |
| 647 | + int nq = trans->cfg->base_params->num_of_queues; | |
| 642 | 648 | int chan; |
| 643 | 649 | u32 reg_val; |
| 650 | + int clear_dwords = (SCD_TRANS_TBL_OFFSET_QUEUE(nq) - | |
| 651 | + SCD_CONTEXT_MEM_LOWER_BOUND) / sizeof(u32); | |
| 644 | 652 | |
| 645 | 653 | /* make sure all queue are not stopped/used */ |
| 646 | 654 | memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped)); |
| @@ -652,20 +660,10 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) · 5 unmodified lines | ||
| 652 | 660 | WARN_ON(scd_base_addr != 0 && |
| 653 | 661 | scd_base_addr != trans_pcie->scd_base_addr); |
| 654 | 662 | |
| 655 | − a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND; | |
| 656 | − /* reset conext data memory */ | |
| 657 | − for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND; | |
| 658 | − a += 4) | |
| 659 | − iwl_write_targ_mem(trans, a, 0); | |
| 660 | − /* reset tx status memory */ | |
| 661 | − for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND; | |
| 662 | − a += 4) | |
| 663 | − iwl_write_targ_mem(trans, a, 0); | |
| 664 | − for (; a < trans_pcie->scd_base_addr + | |
| 665 | − SCD_TRANS_TBL_OFFSET_QUEUE( | |
| 666 | − trans->cfg->base_params->num_of_queues); | |
| 667 | − a += 4) | |
| 668 | − iwl_write_targ_mem(trans, a, 0); | |
| 663 | + /* reset context data, TX status and translation data */ | |
| 664 | + iwl_trans_write_mem(trans, trans_pcie->scd_base_addr + | |
| 665 | + SCD_CONTEXT_MEM_LOWER_BOUND, | |
| 666 | + NULL, clear_dwords); | |
| 669 | 667 | |
| 670 | 668 | iwl_write_prph(trans, SCD_DRAM_BASE_ADDR, |
| 671 | 669 | trans_pcie->scd_bc_tbls.dma >> 10); |
| @@ -697,6 +695,29 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) · 25 unmodified lines | ||
| 697 | 695 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); |
| 698 | 696 | } |
| 699 | 697 | |
| 698 | +void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) | |
| 699 | +{ | |
| 700 | + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | |
| 701 | + int txq_id; | |
| 702 | + | |
| 703 | + for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; | |
| 704 | + txq_id++) { | |
| 705 | + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; | |
| 706 | + | |
| 707 | + iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id), | |
| 708 | + txq->q.dma_addr >> 8); | |
| 709 | + iwl_pcie_txq_unmap(trans, txq_id); | |
| 710 | + txq->q.read_ptr = 0; | |
| 711 | + txq->q.write_ptr = 0; | |
| 712 | + } | |
| 713 | + | |
| 714 | + /* Tell NIC where to find the "keep warm" buffer */ | |
| 715 | + iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, | |
| 716 | + trans_pcie->kw.dma >> 4); | |
| 717 | + | |
| 718 | + iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr); | |
| 719 | +} | |
| 720 | + | |
| 700 | 721 | /* |
| 701 | 722 | * iwl_pcie_tx_stop - Stop all Tx DMA channels |
| 702 | 723 | */ |
| @@ -1002,14 +1023,14 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, · 299 unmodified lines | ||
| 1002 | 1023 | tbl_dw_addr = trans_pcie->scd_base_addr + |
| 1003 | 1024 | SCD_TRANS_TBL_OFFSET_QUEUE(txq_id); |
| 1004 | 1025 | |
| 1005 | − tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr); | |
| 1026 | + tbl_dw = iwl_trans_read_mem32(trans, tbl_dw_addr); | |
| 1006 | 1027 | |
| 1007 | 1028 | if (txq_id & 0x1) |
| 1008 | 1029 | tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); |
| 1009 | 1030 | else |
| 1010 | 1031 | tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); |
| 1011 | 1032 | |
| 1012 | − iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw); | |
| 1033 | + iwl_trans_write_mem32(trans, tbl_dw_addr, tbl_dw); | |
| 1013 | 1034 | |
| 1014 | 1035 | return 0; |
| 1015 | 1036 | } |
| @@ -1068,9 +1089,9 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, · 52 unmodified lines | ||
| 1068 | 1089 | iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn); |
| 1069 | 1090 | |
| 1070 | 1091 | /* Set up Tx window size and frame limit for this queue */ |
| 1071 | − iwl_write_targ_mem(trans, trans_pcie->scd_base_addr + | |
| 1092 | + iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + | |
| 1072 | 1093 | SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0); |
| 1073 | − iwl_write_targ_mem(trans, trans_pcie->scd_base_addr + | |
| 1094 | + iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + | |
| 1074 | 1095 | SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), |
| 1075 | 1096 | ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & |
| 1076 | 1097 | SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | |
| @@ -1101,8 +1122,8 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) · 24 unmodified lines | ||
| 1101 | 1122 | |
| 1102 | 1123 | iwl_pcie_txq_set_inactive(trans, txq_id); |
| 1103 | 1124 | |
| 1104 | − _iwl_write_targ_mem_dwords(trans, stts_addr, | |
| 1105 | − zero_val, ARRAY_SIZE(zero_val)); | |
| 1125 | + iwl_trans_write_mem(trans, stts_addr, (void *)zero_val, | |
| 1126 | + ARRAY_SIZE(zero_val)); | |
| 1106 | 1127 | |
| 1107 | 1128 | iwl_pcie_txq_unmap(trans, txq_id); |
| 1108 | 1129 | |
| @@ -1642,10 +1663,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, · 533 unmodified lines | ||
| 1642 | 1663 | tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); |
| 1643 | 1664 | tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); |
| 1644 | 1665 | |
| 1645 | − IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n", | |
| 1646 | − le16_to_cpu(dev_cmd->hdr.sequence)); | |
| 1647 | − IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); | |
| 1648 | − | |
| 1649 | 1666 | /* Set up entry for this TFD in Tx byte-count array */ |
| 1650 | 1667 | iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); |
| 1651 | 1668 | |
| @@ -363,6 +363,8 @@ struct mac80211_hwsim_data { · 362 unmodified lines | ||
| 363 | 363 | /* difference between this hw's clock and the real clock, in usecs */ |
| 364 | 364 | s64 tsf_offset; |
| 365 | 365 | s64 bcn_delta; |
| 366 | + /* absolute beacon transmission time. Used to cover up "tx" delay. */ | |
| 367 | + u64 abs_bcn_ts; | |
| 366 | 368 | }; |
| 367 | 369 | |
| 368 | 370 | |
| @@ -410,15 +412,19 @@ static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, · 41 unmodified lines | ||
| 410 | 412 | return NETDEV_TX_OK; |
| 411 | 413 | } |
| 412 | 414 | |
| 415 | +static inline u64 mac80211_hwsim_get_tsf_raw(void) | |
| 416 | +{ | |
| 417 | + return ktime_to_us(ktime_get_real()); | |
| 418 | +} | |
| 419 | + | |
| 413 | 420 | static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data) |
| 414 | 421 | { |
| 415 | − struct timeval tv = ktime_to_timeval(ktime_get_real()); | |
| 416 | − u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec; | |
| 422 | + u64 now = mac80211_hwsim_get_tsf_raw(); | |
| 417 | 423 | return cpu_to_le64(now + data->tsf_offset); |
| 418 | 424 | } |
| 419 | 425 | |
| 420 | 426 | static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw, |
| 421 | − struct ieee80211_vif *vif) | |
| 427 | + struct ieee80211_vif *vif) | |
| 422 | 428 | { |
| 423 | 429 | struct mac80211_hwsim_data *data = hw->priv; |
| 424 | 430 | return le64_to_cpu(__mac80211_hwsim_get_tsf(data)); |
| @@ -705,7 +711,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, · 280 unmodified lines | ||
| 705 | 711 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
| 706 | 712 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 707 | 713 | struct ieee80211_rx_status rx_status; |
| 708 | − struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); | |
| 714 | + u64 now; | |
| 709 | 715 | |
| 710 | 716 | memset(&rx_status, 0, sizeof(rx_status)); |
| 711 | 717 | rx_status.flag |= RX_FLAG_MACTIME_START; |
| @@ -731,11 +737,23 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, · 19 unmodified lines | ||
| 731 | 737 | secpath_reset(skb); |
| 732 | 738 | nf_reset(skb); |
| 733 | 739 | |
| 740 | + /* | |
| 741 | + * Get absolute mactime here so all HWs RX at the "same time", and | |
| 742 | + * absolute TX time for beacon mactime so the timestamp matches. | |
| 743 | + * Giving beacons a different mactime than non-beacons looks messy, but | |
| 744 | + * it helps the Toffset be exact and a ~10us mactime discrepancy | |
| 745 | + * probably doesn't really matter. | |
| 746 | + */ | |
| 747 | + if (ieee80211_is_beacon(hdr->frame_control) || | |
| 748 | + ieee80211_is_probe_resp(hdr->frame_control)) | |
| 749 | + now = data->abs_bcn_ts; | |
| 750 | + else | |
| 751 | + now = mac80211_hwsim_get_tsf_raw(); | |
| 752 | + | |
| 734 | 753 | /* Copy skb to all enabled radios that are on the current frequency */ |
| 735 | 754 | spin_lock(&hwsim_radio_lock); |
| 736 | 755 | list_for_each_entry(data2, &hwsim_radios, list) { |
| 737 | 756 | struct sk_buff *nskb; |
| 738 | − struct ieee80211_mgmt *mgmt; | |
| 739 | 757 | struct tx_iter_data tx_iter_data = { |
| 740 | 758 | .receive = false, |
| 741 | 759 | .channel = chan, |
| @@ -787,17 +805,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, · 45 unmodified lines | ||
| 787 | 805 | if (mac80211_hwsim_addr_match(data2, hdr->addr1)) |
| 788 | 806 | ack = true; |
| 789 | 807 | |
| 790 | − /* set bcn timestamp relative to receiver mactime */ | |
| 791 | − rx_status.mactime = | |
| 792 | − le64_to_cpu(__mac80211_hwsim_get_tsf(data2)); | |
| 793 | − mgmt = (struct ieee80211_mgmt *) nskb->data; | |
| 794 | − if (ieee80211_is_beacon(mgmt->frame_control) || | |
| 795 | − ieee80211_is_probe_resp(mgmt->frame_control)) | |
| 796 | − mgmt->u.beacon.timestamp = cpu_to_le64( | |
| 797 | − rx_status.mactime + | |
| 798 | − (data->tsf_offset - data2->tsf_offset) + | |
| 799 | − 24 * 8 * 10 / txrate->bitrate); | |
| 800 | − | |
| 808 | + rx_status.mactime = now + data2->tsf_offset; | |
| 801 | 809 | #if 0 |
| 802 | 810 | /* |
| 803 | 811 | * Don't enable this code by default as the OUI 00:00:00 |
| @@ -987,7 +995,11 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, · 183 unmodified lines | ||
| 987 | 995 | static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, |
| 988 | 996 | struct ieee80211_vif *vif) |
| 989 | 997 | { |
| 990 | − struct ieee80211_hw *hw = arg; | |
| 998 | + struct mac80211_hwsim_data *data = arg; | |
| 999 | + struct ieee80211_hw *hw = data->hw; | |
| 1000 | + struct ieee80211_tx_info *info; | |
| 1001 | + struct ieee80211_rate *txrate; | |
| 1002 | + struct ieee80211_mgmt *mgmt; | |
| 991 | 1003 | struct sk_buff *skb; |
| 992 | 1004 | |
| 993 | 1005 | hwsim_check_magic(vif); |
| @@ -1000,6 +1012,15 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, · 6 unmodified lines | ||
| 1000 | 1012 | skb = ieee80211_beacon_get(hw, vif); |
| 1001 | 1013 | if (skb == NULL) |
| 1002 | 1014 | return; |
| 1015 | + info = IEEE80211_SKB_CB(skb); | |
| 1016 | + txrate = ieee80211_get_tx_rate(hw, info); | |
| 1017 | + | |
| 1018 | + mgmt = (struct ieee80211_mgmt *) skb->data; | |
| 1019 | + /* fake header transmission time */ | |
| 1020 | + data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw(); | |
| 1021 | + mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts + | |
| 1022 | + data->tsf_offset + | |
| 1023 | + 24 * 8 * 10 / txrate->bitrate); | |
| 1003 | 1024 | |
| 1004 | 1025 | mac80211_hwsim_tx_frame(hw, skb, |
| 1005 | 1026 | rcu_dereference(vif->chanctx_conf)->def.chan); |
| @@ -1020,7 +1041,7 @@ mac80211_hwsim_beacon(struct hrtimer *timer) · 14 unmodified lines | ||
| 1020 | 1041 | |
| 1021 | 1042 | ieee80211_iterate_active_interfaces_atomic( |
| 1022 | 1043 | hw, IEEE80211_IFACE_ITER_NORMAL, |
| 1023 | − mac80211_hwsim_beacon_tx, hw); | |
| 1044 | + mac80211_hwsim_beacon_tx, data); | |
| 1024 | 1045 | |
| 1025 | 1046 | /* beacon at new TBTT + beacon interval */ |
| 1026 | 1047 | if (data->bcn_delta) { |
| @@ -53,7 +53,9 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, · 52 unmodified lines | ||
| 53 | 53 | sizeof(sband->ht_cap.mcs)); |
| 54 | 54 | |
| 55 | 55 | if (priv->bss_mode == NL80211_IFTYPE_STATION || |
| 56 | − sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | |
| 56 | + (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && | |
| 57 | + (priv->adapter->sec_chan_offset != | |
| 58 | + IEEE80211_HT_PARAM_CHA_SEC_NONE))) | |
| 57 | 59 | /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ |
| 58 | 60 | SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); |
| 59 | 61 | |
| @@ -278,14 +278,16 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, · 277 unmodified lines | ||
| 278 | 278 | dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); |
| 279 | 279 | break; |
| 280 | 280 | case -1: |
| 281 | − adapter->data_sent = false; | |
| 281 | + if (adapter->iface_type != MWIFIEX_PCIE) | |
| 282 | + adapter->data_sent = false; | |
| 282 | 283 | dev_err(adapter->dev, "%s: host_to_card failed: %#x\n", |
| 283 | 284 | __func__, ret); |
| 284 | 285 | adapter->dbg.num_tx_host_to_card_failure++; |
| 285 | 286 | mwifiex_write_data_complete(adapter, skb_aggr, 1, ret); |
| 286 | 287 | return 0; |
| 287 | 288 | case -EINPROGRESS: |
| 288 | − adapter->data_sent = false; | |
| 289 | + if (adapter->iface_type != MWIFIEX_PCIE) | |
| 290 | + adapter->data_sent = false; | |
| 289 | 291 | break; |
| 290 | 292 | case 0: |
| 291 | 293 | mwifiex_write_data_complete(adapter, skb_aggr, 1, ret); |
| @@ -1325,6 +1325,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, · 1324 unmodified lines | ||
| 1325 | 1325 | } |
| 1326 | 1326 | |
| 1327 | 1327 | mwifiex_set_ht_params(priv, bss_cfg, params); |
| 1328 | + mwifiex_set_wmm_params(priv, bss_cfg, params); | |
| 1328 | 1329 | |
| 1329 | 1330 | if (params->inactivity_timeout > 0) { |
| 1330 | 1331 | /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ |
| @@ -1457,7 +1458,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, · 126 unmodified lines | ||
| 1457 | 1458 | struct cfg80211_ssid req_ssid; |
| 1458 | 1459 | int ret, auth_type = 0; |
| 1459 | 1460 | struct cfg80211_bss *bss = NULL; |
| 1460 | − u8 is_scanning_required = 0, config_bands = 0; | |
| 1461 | + u8 is_scanning_required = 0; | |
| 1461 | 1462 | |
| 1462 | 1463 | memset(&req_ssid, 0, sizeof(struct cfg80211_ssid)); |
| 1463 | 1464 | |
| @@ -1476,19 +1477,6 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, · 12 unmodified lines | ||
| 1476 | 1477 | /* disconnect before try to associate */ |
| 1477 | 1478 | mwifiex_deauthenticate(priv, NULL); |
| 1478 | 1479 | |
| 1479 | − if (channel) { | |
| 1480 | − if (mode == NL80211_IFTYPE_STATION) { | |
| 1481 | − if (channel->band == IEEE80211_BAND_2GHZ) | |
| 1482 | − config_bands = BAND_B | BAND_G | BAND_GN; | |
| 1483 | − else | |
| 1484 | − config_bands = BAND_A | BAND_AN; | |
| 1485 | − | |
| 1486 | − if (!((config_bands | priv->adapter->fw_bands) & | |
| 1487 | − ~priv->adapter->fw_bands)) | |
| 1488 | − priv->adapter->config_bands = config_bands; | |
| 1489 | − } | |
| 1490 | − } | |
| 1491 | − | |
| 1492 | 1480 | /* As this is new association, clear locally stored |
| 1493 | 1481 | * keys and security related flags */ |
| 1494 | 1482 | priv->sec_info.wpa_enabled = false; |
| @@ -1705,9 +1693,9 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv, · 210 unmodified lines | ||
| 1705 | 1693 | |
| 1706 | 1694 | if (cfg80211_get_chandef_type(¶ms->chandef) != |
| 1707 | 1695 | NL80211_CHAN_NO_HT) |
| 1708 | − config_bands |= BAND_GN; | |
| 1696 | + config_bands |= BAND_G | BAND_GN; | |
| 1709 | 1697 | } else { |
| 1710 | − if (cfg80211_get_chandef_type(¶ms->chandef) != | |
| 1698 | + if (cfg80211_get_chandef_type(¶ms->chandef) == | |
| 1711 | 1699 | NL80211_CHAN_NO_HT) |
| 1712 | 1700 | config_bands = BAND_A; |
| 1713 | 1701 | else |
| @@ -2259,6 +2247,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) · 545 unmodified lines | ||
| 2259 | 2247 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
| 2260 | 2248 | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | |
| 2261 | 2249 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | |
| 2250 | + WIPHY_FLAG_AP_UAPSD | | |
| 2262 | 2251 | WIPHY_FLAG_CUSTOM_REGULATORY | |
| 2263 | 2252 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
| 2264 | 2253 | |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | #include <linux/wait.h> |
| 27 | 27 | #include <linux/timer.h> |
| 28 | 28 | #include <linux/ieee80211.h> |
| 29 | +#include <net/mac80211.h> | |
| 29 | 30 | |
| 30 | 31 | |
| 31 | 32 | #define MWIFIEX_MAX_BSS_NUM (3) |
| @@ -58,6 +59,8 @@ · 26 unmodified lines | ||
| 58 | 59 | #define MWIFIEX_RTS_MAX_VALUE (2347) |
| 59 | 60 | #define MWIFIEX_FRAG_MIN_VALUE (256) |
| 60 | 61 | #define MWIFIEX_FRAG_MAX_VALUE (2346) |
| 62 | +#define MWIFIEX_WMM_VERSION 0x01 | |
| 63 | +#define MWIFIEX_WMM_SUBTYPE 0x01 | |
| 61 | 64 | |
| 62 | 65 | #define MWIFIEX_RETRY_LIMIT 14 |
| 63 | 66 | #define MWIFIEX_SDIO_BLOCK_SIZE 256 |
| @@ -126,4 +129,19 @@ enum mwifiex_wmm_ac_e { · 62 unmodified lines | ||
| 126 | 129 | WMM_AC_VI, |
| 127 | 130 | WMM_AC_VO |
| 128 | 131 | } __packed; |
| 132 | + | |
| 133 | +struct ieee_types_wmm_ac_parameters { | |
| 134 | + u8 aci_aifsn_bitmap; | |
| 135 | + u8 ecw_bitmap; | |
| 136 | + __le16 tx_op_limit; | |
| 137 | +} __packed; | |
| 138 | + | |
| 139 | +struct mwifiex_types_wmm_info { | |
| 140 | + u8 oui[4]; | |
| 141 | + u8 subtype; | |
| 142 | + u8 version; | |
| 143 | + u8 qos_info; | |
| 144 | + u8 reserved; | |
| 145 | + struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS]; | |
| 146 | +} __packed; | |
| 129 | 147 | #endif /* !_MWIFIEX_DECL_H_ */ |
| @@ -330,6 +330,9 @@ enum P2P_MODES { · 329 unmodified lines | ||
| 330 | 330 | #define HOST_SLEEP_CFG_GPIO_DEF 0xff |
| 331 | 331 | #define HOST_SLEEP_CFG_GAP_DEF 0 |
| 332 | 332 | |
| 333 | +#define MWIFIEX_TIMEOUT_FOR_AP_RESP 0xfffc | |
| 334 | +#define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT 2 | |
| 335 | + | |
| 333 | 336 | #define CMD_F_HOSTCMD (1 << 0) |
| 334 | 337 | #define CMD_F_CANCELED (1 << 1) |
| 335 | 338 | |
| @@ -1131,12 +1134,6 @@ struct ieee_types_vendor_header { · 795 unmodified lines | ||
| 1131 | 1134 | u8 version; |
| 1132 | 1135 | } __packed; |
| 1133 | 1136 | |
| 1134 | −struct ieee_types_wmm_ac_parameters { | |
| 1135 | − u8 aci_aifsn_bitmap; | |
| 1136 | − u8 ecw_bitmap; | |
| 1137 | − __le16 tx_op_limit; | |
| 1138 | −} __packed; | |
| 1139 | − | |
| 1140 | 1137 | struct ieee_types_wmm_parameter { |
| 1141 | 1138 | /* |
| 1142 | 1139 | * WMM Parameter IE - Vendor Specific Header: |
| @@ -1186,6 +1183,11 @@ struct mwifiex_ie_types_htcap { · 43 unmodified lines | ||
| 1186 | 1183 | struct ieee80211_ht_cap ht_cap; |
| 1187 | 1184 | } __packed; |
| 1188 | 1185 | |
| 1186 | +struct mwifiex_ie_types_wmmcap { | |
| 1187 | + struct mwifiex_ie_types_header header; | |
| 1188 | + struct mwifiex_types_wmm_info wmm_info; | |
| 1189 | +} __packed; | |
| 1190 | + | |
| 1189 | 1191 | struct mwifiex_ie_types_htinfo { |
| 1190 | 1192 | struct mwifiex_ie_types_header header; |
| 1191 | 1193 | struct ieee80211_ht_operation ht_oper; |
| @@ -591,6 +591,12 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter) · 590 unmodified lines | ||
| 591 | 591 | return -1; |
| 592 | 592 | } |
| 593 | 593 | } |
| 594 | + | |
| 595 | + if (adapter->if_ops.init_fw_port) { | |
| 596 | + if (adapter->if_ops.init_fw_port(adapter)) | |
| 597 | + return -1; | |
| 598 | + } | |
| 599 | + | |
| 594 | 600 | for (i = 0; i < adapter->priv_num; i++) { |
| 595 | 601 | if (adapter->priv[i]) { |
| 596 | 602 | ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta); |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | ||
| 20 | 20 | #ifndef _MWIFIEX_IOCTL_H_ |
| 21 | 21 | #define _MWIFIEX_IOCTL_H_ |
| 22 | 22 | |
| 23 | −#include <net/mac80211.h> | |
| 24 | 23 | #include <net/lib80211.h> |
| 25 | 24 | |
| 26 | 25 | enum { |
| @@ -107,6 +106,8 @@ struct mwifiex_uap_bss_param { · 80 unmodified lines | ||
| 107 | 106 | u8 rates[MWIFIEX_SUPPORTED_RATES]; |
| 108 | 107 | u32 sta_ao_timer; |
| 109 | 108 | u32 ps_sta_ao_timer; |
| 109 | + u8 qos_info; | |
| 110 | + struct mwifiex_types_wmm_info wmm_info; | |
| 110 | 111 | }; |
| 111 | 112 | |
| 112 | 113 | enum { |
| @@ -615,23 +615,33 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, · 614 unmodified lines | ||
| 615 | 615 | struct ieee_types_assoc_rsp *assoc_rsp; |
| 616 | 616 | struct mwifiex_bssdescriptor *bss_desc; |
| 617 | 617 | u8 enable_data = true; |
| 618 | + u16 cap_info, status_code; | |
| 618 | 619 | |
| 619 | 620 | assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; |
| 620 | 621 | |
| 622 | + cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap); | |
| 623 | + status_code = le16_to_cpu(assoc_rsp->status_code); | |
| 624 | + | |
| 621 | 625 | priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, |
| 622 | 626 | sizeof(priv->assoc_rsp_buf)); |
| 623 | 627 | |
| 624 | 628 | memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); |
| 625 | 629 | |
| 626 | − if (le16_to_cpu(assoc_rsp->status_code)) { | |
| 630 | + if (status_code) { | |
| 627 | 631 | priv->adapter->dbg.num_cmd_assoc_failure++; |
| 628 | 632 | dev_err(priv->adapter->dev, |
| 629 | 633 | "ASSOC_RESP: failed, status code=%d err=%#x a_id=%#x\n", |
| 630 | − le16_to_cpu(assoc_rsp->status_code), | |
| 631 | − le16_to_cpu(assoc_rsp->cap_info_bitmap), | |
| 632 | − le16_to_cpu(assoc_rsp->a_id)); | |
| 634 | + status_code, cap_info, le16_to_cpu(assoc_rsp->a_id)); | |
| 635 | + | |
| 636 | + if (cap_info == MWIFIEX_TIMEOUT_FOR_AP_RESP) { | |
| 637 | + if (status_code == MWIFIEX_STATUS_CODE_AUTH_TIMEOUT) | |
| 638 | + ret = WLAN_STATUS_AUTH_TIMEOUT; | |
| 639 | + else | |
| 640 | + ret = WLAN_STATUS_UNSPECIFIED_FAILURE; | |
| 641 | + } else { | |
| 642 | + ret = status_code; | |
| 643 | + } | |
| 633 | 644 | |
| 634 | − ret = le16_to_cpu(assoc_rsp->status_code); | |
| 635 | 645 | goto done; |
| 636 | 646 | } |
| 637 | 647 | |
| @@ -969,6 +979,16 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, · 331 unmodified lines | ||
| 969 | 979 | priv->adapter->config_bands); |
| 970 | 980 | mwifiex_fill_cap_info(priv, radio_type, ht_cap); |
| 971 | 981 | |
| 982 | + if (adapter->sec_chan_offset == | |
| 983 | + IEEE80211_HT_PARAM_CHA_SEC_NONE) { | |
| 984 | + u16 tmp_ht_cap; | |
| 985 | + | |
| 986 | + tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info); | |
| 987 | + tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | |
| 988 | + tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40; | |
| 989 | + ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap); | |
| 990 | + } | |
| 991 | + | |
| 972 | 992 | pos += sizeof(struct mwifiex_ie_types_htcap); |
| 973 | 993 | cmd_append_size += sizeof(struct mwifiex_ie_types_htcap); |
| 974 | 994 | |
| @@ -599,8 +599,10 @@ struct mwifiex_if_ops { · 598 unmodified lines | ||
| 599 | 599 | int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); |
| 600 | 600 | int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); |
| 601 | 601 | int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *); |
| 602 | + int (*init_fw_port) (struct mwifiex_adapter *); | |
| 602 | 603 | int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); |
| 603 | 604 | void (*card_reset) (struct mwifiex_adapter *); |
| 605 | + int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); | |
| 604 | 606 | }; |
| 605 | 607 | |
| 606 | 608 | struct mwifiex_adapter { |
| @@ -890,6 +892,10 @@ void mwifiex_set_ht_params(struct mwifiex_private *priv, · 283 unmodified lines | ||
| 890 | 892 | struct cfg80211_ap_settings *params); |
| 891 | 893 | void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg, |
| 892 | 894 | struct cfg80211_ap_settings *params); |
| 895 | +void | |
| 896 | +mwifiex_set_wmm_params(struct mwifiex_private *priv, | |
| 897 | + struct mwifiex_uap_bss_param *bss_cfg, | |
| 898 | + struct cfg80211_ap_settings *params); | |
| 893 | 899 | |
| 894 | 900 | /* |
| 895 | 901 | * This function checks if the queuing is RA based or not. |
| @@ -39,17 +39,20 @@ static struct semaphore add_remove_card_sem; · 38 unmodified lines | ||
| 39 | 39 | static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter); |
| 40 | 40 | static int mwifiex_pcie_resume(struct pci_dev *pdev); |
| 41 | 41 | |
| 42 | −/* | |
| 43 | − * This function is called after skb allocation to update | |
| 44 | − * "skb->cb" with physical address of data pointer. | |
| 45 | − */ | |
| 46 | −static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb) | |
| 42 | +static int | |
| 43 | +mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb, | |
| 44 | + int size, int flags) | |
| 47 | 45 | { |
| 48 | − phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb); | |
| 49 | − | |
| 50 | − *buf_pa = (phys_addr_t)virt_to_phys(skb->data); | |
| 46 | + struct pcie_service_card *card = adapter->card; | |
| 47 | + dma_addr_t buf_pa; | |
| 51 | 48 | |
| 52 | − return buf_pa; | |
| 49 | + buf_pa = pci_map_single(card->dev, skb->data, size, flags); | |
| 50 | + if (pci_dma_mapping_error(card->dev, buf_pa)) { | |
| 51 | + dev_err(adapter->dev, "failed to map pci memory!\n"); | |
| 52 | + return -1; | |
| 53 | + } | |
| 54 | + memcpy(skb->cb, &buf_pa, sizeof(dma_addr_t)); | |
| 55 | + return 0; | |
| 53 | 56 | } |
| 54 | 57 | |
| 55 | 58 | /* |
| @@ -60,8 +63,8 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) · 4 unmodified lines | ||
| 60 | 63 | u32 *cookie_addr; |
| 61 | 64 | struct pcie_service_card *card = adapter->card; |
| 62 | 65 | |
| 63 | − if (card->sleep_cookie) { | |
| 64 | − cookie_addr = (u32 *)card->sleep_cookie->data; | |
| 66 | + if (card->sleep_cookie_vbase) { | |
| 67 | + cookie_addr = (u32 *)card->sleep_cookie_vbase; | |
| 65 | 68 | dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n", |
| 66 | 69 | *cookie_addr); |
| 67 | 70 | if (*cookie_addr == FW_AWAKE_COOKIE) |
| @@ -161,7 +164,7 @@ static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state) · 93 unmodified lines | ||
| 161 | 164 | |
| 162 | 165 | if (pdev) { |
| 163 | 166 | card = (struct pcie_service_card *) pci_get_drvdata(pdev); |
| 164 | − if (!card || card->adapter) { | |
| 167 | + if (!card || !card->adapter) { | |
| 165 | 168 | pr_err("Card or adapter structure is not valid\n"); |
| 166 | 169 | return 0; |
| 167 | 170 | } |
| @@ -366,9 +369,7 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter) · 198 unmodified lines | ||
| 366 | 369 | static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) |
| 367 | 370 | { |
| 368 | 371 | struct pcie_service_card *card = adapter->card; |
| 369 | − struct sk_buff *skb; | |
| 370 | 372 | int i; |
| 371 | − phys_addr_t *buf_pa; | |
| 372 | 373 | |
| 373 | 374 | /* |
| 374 | 375 | * driver maintaines the write pointer and firmware maintaines the read |
| @@ -384,16 +385,18 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) · 9 unmodified lines | ||
| 384 | 385 | MWIFIEX_MAX_TXRX_BD; |
| 385 | 386 | dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n", |
| 386 | 387 | card->txbd_ring_size); |
| 387 | − card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL); | |
| 388 | + card->txbd_ring_vbase = pci_alloc_consistent(card->dev, | |
| 389 | + card->txbd_ring_size, | |
| 390 | + &card->txbd_ring_pbase); | |
| 388 | 391 | if (!card->txbd_ring_vbase) { |
| 389 | − dev_err(adapter->dev, "Unable to alloc buffer for txbd ring\n"); | |
| 392 | + dev_err(adapter->dev, | |
| 393 | + "allocate consistent memory (%d bytes) failed!\n", | |
| 394 | + card->txbd_ring_size); | |
| 390 | 395 | return -ENOMEM; |
| 391 | 396 | } |
| 392 | − card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase); | |
| 393 | − | |
| 394 | 397 | dev_dbg(adapter->dev, |
| 395 | 398 | "info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n", |
| 396 | − card->txbd_ring_vbase, (u32)card->txbd_ring_pbase, | |
| 399 | + card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase, | |
| 397 | 400 | (u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size); |
| 398 | 401 | |
| 399 | 402 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { |
| @@ -402,24 +405,9 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) · 2 unmodified lines | ||
| 402 | 405 | (sizeof(struct mwifiex_pcie_buf_desc) |
| 403 | 406 | * i)); |
| 404 | 407 | |
| 405 | − /* Allocate buffer here so that firmware can DMA data from it */ | |
| 406 | − skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); | |
| 407 | − if (!skb) { | |
| 408 | − dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n"); | |
| 409 | − kfree(card->txbd_ring_vbase); | |
| 410 | − return -ENOMEM; | |
| 411 | − } | |
| 412 | − buf_pa = mwifiex_update_sk_buff_pa(skb); | |
| 413 | − | |
| 414 | − skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE); | |
| 415 | − dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, " | |
| 416 | − "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", | |
| 417 | − skb, skb->data, (u32)*buf_pa, | |
| 418 | − (u32)(((u64)*buf_pa >> 32)), skb->len); | |
| 419 | − | |
| 420 | − card->tx_buf_list[i] = skb; | |
| 421 | − card->txbd_ring[i]->paddr = *buf_pa; | |
| 422 | − card->txbd_ring[i]->len = (u16)skb->len; | |
| 408 | + card->tx_buf_list[i] = NULL; | |
| 409 | + card->txbd_ring[i]->paddr = 0; | |
| 410 | + card->txbd_ring[i]->len = 0; | |
| 423 | 411 | card->txbd_ring[i]->flags = 0; |
| 424 | 412 | } |
| 425 | 413 | |
| @@ -429,11 +417,16 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) · 3 unmodified lines | ||
| 429 | 417 | static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) |
| 430 | 418 | { |
| 431 | 419 | struct pcie_service_card *card = adapter->card; |
| 420 | + struct sk_buff *skb; | |
| 432 | 421 | int i; |
| 433 | 422 | |
| 434 | 423 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { |
| 435 | − if (card->tx_buf_list[i]) | |
| 436 | − dev_kfree_skb_any(card->tx_buf_list[i]); | |
| 424 | + if (card->tx_buf_list[i]) { | |
| 425 | + skb = card->tx_buf_list[i]; | |
| 426 | + pci_unmap_single(card->dev, card->txbd_ring[i]->paddr, | |
| 427 | + skb->len, PCI_DMA_TODEVICE); | |
| 428 | + dev_kfree_skb_any(skb); | |
| 429 | + } | |
| 437 | 430 | card->tx_buf_list[i] = NULL; |
| 438 | 431 | card->txbd_ring[i]->paddr = 0; |
| 439 | 432 | card->txbd_ring[i]->len = 0; |
| @@ -441,11 +434,15 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) · 1 unmodified line | ||
| 441 | 434 | card->txbd_ring[i] = NULL; |
| 442 | 435 | } |
| 443 | 436 | |
| 444 | − kfree(card->txbd_ring_vbase); | |
| 437 | + if (card->txbd_ring_vbase) | |
| 438 | + pci_free_consistent(card->dev, card->txbd_ring_size, | |
| 439 | + card->txbd_ring_vbase, | |
| 440 | + card->txbd_ring_pbase); | |
| 445 | 441 | card->txbd_ring_size = 0; |
| 446 | 442 | card->txbd_wrptr = 0; |
| 447 | 443 | card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; |
| 448 | 444 | card->txbd_ring_vbase = NULL; |
| 445 | + card->txbd_ring_pbase = 0; | |
| 449 | 446 | |
| 450 | 447 | return 0; |
| 451 | 448 | } |
| @@ -458,7 +455,7 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) · 6 unmodified lines | ||
| 458 | 455 | struct pcie_service_card *card = adapter->card; |
| 459 | 456 | struct sk_buff *skb; |
| 460 | 457 | int i; |
| 461 | − phys_addr_t *buf_pa; | |
| 458 | + dma_addr_t buf_pa; | |
| 462 | 459 | |
| 463 | 460 | /* |
| 464 | 461 | * driver maintaines the read pointer and firmware maintaines the write |
| @@ -472,13 +469,15 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) · 7 unmodified lines | ||
| 472 | 469 | MWIFIEX_MAX_TXRX_BD; |
| 473 | 470 | dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n", |
| 474 | 471 | card->rxbd_ring_size); |
| 475 | − card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL); | |
| 472 | + card->rxbd_ring_vbase = pci_alloc_consistent(card->dev, | |
| 473 | + card->rxbd_ring_size, | |
| 474 | + &card->rxbd_ring_pbase); | |
| 476 | 475 | if (!card->rxbd_ring_vbase) { |
| 477 | − dev_err(adapter->dev, "Unable to allocate buffer for " | |
| 478 | − "rxbd_ring.\n"); | |
| 476 | + dev_err(adapter->dev, | |
| 477 | + "allocate consistent memory (%d bytes) failed!\n", | |
| 478 | + card->rxbd_ring_size); | |
| 479 | 479 | return -ENOMEM; |
| 480 | 480 | } |
| 481 | − card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase); | |
| 482 | 481 | |
| 483 | 482 | dev_dbg(adapter->dev, |
| 484 | 483 | "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n", |
| @@ -500,16 +499,20 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) · 15 unmodified lines | ||
| 500 | 499 | kfree(card->rxbd_ring_vbase); |
| 501 | 500 | return -ENOMEM; |
| 502 | 501 | } |
| 503 | − buf_pa = mwifiex_update_sk_buff_pa(skb); | |
| 504 | − skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE); | |
| 502 | + if (mwifiex_map_pci_memory(adapter, skb, | |
| 503 | + MWIFIEX_RX_DATA_BUF_SIZE, | |
| 504 | + PCI_DMA_FROMDEVICE)) | |
| 505 | + return -1; | |
| 506 | + | |
| 507 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 505 | 508 | |
| 506 | 509 | dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, " |
| 507 | 510 | "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", |
| 508 | − skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32), | |
| 511 | + skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32), | |
| 509 | 512 | skb->len); |
| 510 | 513 | |
| 511 | 514 | card->rx_buf_list[i] = skb; |
| 512 | − card->rxbd_ring[i]->paddr = *buf_pa; | |
| 515 | + card->rxbd_ring[i]->paddr = buf_pa; | |
| 513 | 516 | card->rxbd_ring[i]->len = (u16)skb->len; |
| 514 | 517 | card->rxbd_ring[i]->flags = 0; |
| 515 | 518 | } |
| @@ -523,11 +526,17 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) · 7 unmodified lines | ||
| 523 | 526 | static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) |
| 524 | 527 | { |
| 525 | 528 | struct pcie_service_card *card = adapter->card; |
| 529 | + struct sk_buff *skb; | |
| 526 | 530 | int i; |
| 527 | 531 | |
| 528 | 532 | for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { |
| 529 | − if (card->rx_buf_list[i]) | |
| 530 | − dev_kfree_skb_any(card->rx_buf_list[i]); | |
| 533 | + if (card->rx_buf_list[i]) { | |
| 534 | + skb = card->rx_buf_list[i]; | |
| 535 | + pci_unmap_single(card->dev, card->rxbd_ring[i]->paddr , | |
| 536 | + MWIFIEX_RX_DATA_BUF_SIZE, | |
| 537 | + PCI_DMA_FROMDEVICE); | |
| 538 | + dev_kfree_skb_any(skb); | |
| 539 | + } | |
| 531 | 540 | card->rx_buf_list[i] = NULL; |
| 532 | 541 | card->rxbd_ring[i]->paddr = 0; |
| 533 | 542 | card->rxbd_ring[i]->len = 0; |
| @@ -535,11 +544,15 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) · 1 unmodified line | ||
| 535 | 544 | card->rxbd_ring[i] = NULL; |
| 536 | 545 | } |
| 537 | 546 | |
| 538 | − kfree(card->rxbd_ring_vbase); | |
| 547 | + if (card->rxbd_ring_vbase) | |
| 548 | + pci_free_consistent(card->dev, card->rxbd_ring_size, | |
| 549 | + card->rxbd_ring_vbase, | |
| 550 | + card->rxbd_ring_pbase); | |
| 539 | 551 | card->rxbd_ring_size = 0; |
| 540 | 552 | card->rxbd_wrptr = 0; |
| 541 | 553 | card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; |
| 542 | 554 | card->rxbd_ring_vbase = NULL; |
| 555 | + card->rxbd_ring_pbase = 0; | |
| 543 | 556 | |
| 544 | 557 | return 0; |
| 545 | 558 | } |
| @@ -552,7 +565,7 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) · 6 unmodified lines | ||
| 552 | 565 | struct pcie_service_card *card = adapter->card; |
| 553 | 566 | struct sk_buff *skb; |
| 554 | 567 | int i; |
| 555 | − phys_addr_t *buf_pa; | |
| 568 | + dma_addr_t buf_pa; | |
| 556 | 569 | |
| 557 | 570 | /* |
| 558 | 571 | * driver maintaines the read pointer and firmware maintaines the write |
| @@ -566,13 +579,15 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) · 7 unmodified lines | ||
| 566 | 579 | MWIFIEX_MAX_EVT_BD; |
| 567 | 580 | dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n", |
| 568 | 581 | card->evtbd_ring_size); |
| 569 | − card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL); | |
| 582 | + card->evtbd_ring_vbase = pci_alloc_consistent(card->dev, | |
| 583 | + card->evtbd_ring_size, | |
| 584 | + &card->evtbd_ring_pbase); | |
| 570 | 585 | if (!card->evtbd_ring_vbase) { |
| 571 | 586 | dev_err(adapter->dev, |
| 572 | − "Unable to allocate buffer. Terminating download\n"); | |
| 587 | + "allocate consistent memory (%d bytes) failed!\n", | |
| 588 | + card->evtbd_ring_size); | |
| 573 | 589 | return -ENOMEM; |
| 574 | 590 | } |
| 575 | − card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase); | |
| 576 | 591 | |
| 577 | 592 | dev_dbg(adapter->dev, |
| 578 | 593 | "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n", |
| @@ -594,16 +609,20 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) · 15 unmodified lines | ||
| 594 | 609 | kfree(card->evtbd_ring_vbase); |
| 595 | 610 | return -ENOMEM; |
| 596 | 611 | } |
| 597 | − buf_pa = mwifiex_update_sk_buff_pa(skb); | |
| 598 | 612 | skb_put(skb, MAX_EVENT_SIZE); |
| 599 | 613 | |
| 614 | + if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, | |
| 615 | + PCI_DMA_FROMDEVICE)) | |
| 616 | + return -1; | |
| 617 | + | |
| 618 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 600 | 619 | dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, " |
| 601 | 620 | "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", |
| 602 | − skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32), | |
| 621 | + skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32), | |
| 603 | 622 | skb->len); |
| 604 | 623 | |
| 605 | 624 | card->evt_buf_list[i] = skb; |
| 606 | − card->evtbd_ring[i]->paddr = *buf_pa; | |
| 625 | + card->evtbd_ring[i]->paddr = buf_pa; | |
| 607 | 626 | card->evtbd_ring[i]->len = (u16)skb->len; |
| 608 | 627 | card->evtbd_ring[i]->flags = 0; |
| 609 | 628 | } |
| @@ -617,11 +636,16 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) · 7 unmodified lines | ||
| 617 | 636 | static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter) |
| 618 | 637 | { |
| 619 | 638 | struct pcie_service_card *card = adapter->card; |
| 639 | + struct sk_buff *skb; | |
| 620 | 640 | int i; |
| 621 | 641 | |
| 622 | 642 | for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { |
| 623 | − if (card->evt_buf_list[i]) | |
| 624 | − dev_kfree_skb_any(card->evt_buf_list[i]); | |
| 643 | + if (card->evt_buf_list[i]) { | |
| 644 | + skb = card->evt_buf_list[i]; | |
| 645 | + pci_unmap_single(card->dev, card->evtbd_ring[i]->paddr, | |
| 646 | + MAX_EVENT_SIZE, PCI_DMA_FROMDEVICE); | |
| 647 | + dev_kfree_skb_any(skb); | |
| 648 | + } | |
| 625 | 649 | card->evt_buf_list[i] = NULL; |
| 626 | 650 | card->evtbd_ring[i]->paddr = 0; |
| 627 | 651 | card->evtbd_ring[i]->len = 0; |
| @@ -629,11 +653,15 @@ static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter) · 1 unmodified line | ||
| 629 | 653 | card->evtbd_ring[i] = NULL; |
| 630 | 654 | } |
| 631 | 655 | |
| 632 | − kfree(card->evtbd_ring_vbase); | |
| 656 | + if (card->evtbd_ring_vbase) | |
| 657 | + pci_free_consistent(card->dev, card->evtbd_ring_size, | |
| 658 | + card->evtbd_ring_vbase, | |
| 659 | + card->evtbd_ring_pbase); | |
| 633 | 660 | card->evtbd_wrptr = 0; |
| 634 | 661 | card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; |
| 635 | 662 | card->evtbd_ring_size = 0; |
| 636 | 663 | card->evtbd_ring_vbase = NULL; |
| 664 | + card->evtbd_ring_pbase = 0; | |
| 637 | 665 | |
| 638 | 666 | return 0; |
| 639 | 667 | } |
| @@ -653,21 +681,12 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) · 13 unmodified lines | ||
| 653 | 681 | "Unable to allocate skb for command response data.\n"); |
| 654 | 682 | return -ENOMEM; |
| 655 | 683 | } |
| 656 | − mwifiex_update_sk_buff_pa(skb); | |
| 657 | 684 | skb_put(skb, MWIFIEX_UPLD_SIZE); |
| 658 | − card->cmdrsp_buf = skb; | |
| 685 | + if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, | |
| 686 | + PCI_DMA_FROMDEVICE)) | |
| 687 | + return -1; | |
| 659 | 688 | |
| 660 | − skb = NULL; | |
| 661 | − /* Allocate memory for sending command to firmware */ | |
| 662 | − skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER); | |
| 663 | − if (!skb) { | |
| 664 | − dev_err(adapter->dev, | |
| 665 | − "Unable to allocate skb for command data.\n"); | |
| 666 | − return -ENOMEM; | |
| 667 | − } | |
| 668 | − mwifiex_update_sk_buff_pa(skb); | |
| 669 | − skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER); | |
| 670 | − card->cmd_buf = skb; | |
| 689 | + card->cmdrsp_buf = skb; | |
| 671 | 690 | |
| 672 | 691 | return 0; |
| 673 | 692 | } |
| @@ -678,18 +697,26 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) · 4 unmodified lines | ||
| 678 | 697 | static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) |
| 679 | 698 | { |
| 680 | 699 | struct pcie_service_card *card; |
| 700 | + dma_addr_t buf_pa; | |
| 681 | 701 | |
| 682 | 702 | if (!adapter) |
| 683 | 703 | return 0; |
| 684 | 704 | |
| 685 | 705 | card = adapter->card; |
| 686 | 706 | |
| 687 | − if (card && card->cmdrsp_buf) | |
| 707 | + if (card && card->cmdrsp_buf) { | |
| 708 | + MWIFIEX_SKB_PACB(card->cmdrsp_buf, &buf_pa); | |
| 709 | + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, | |
| 710 | + PCI_DMA_FROMDEVICE); | |
| 688 | 711 | dev_kfree_skb_any(card->cmdrsp_buf); |
| 712 | + } | |
| 689 | 713 | |
| 690 | − if (card && card->cmd_buf) | |
| 714 | + if (card && card->cmd_buf) { | |
| 715 | + MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa); | |
| 716 | + pci_unmap_single(card->dev, buf_pa, MWIFIEX_SIZE_OF_CMD_BUFFER, | |
| 717 | + PCI_DMA_TODEVICE); | |
| 691 | 718 | dev_kfree_skb_any(card->cmd_buf); |
| 692 | − | |
| 719 | + } | |
| 693 | 720 | return 0; |
| 694 | 721 | } |
| 695 | 722 | |
| @@ -698,27 +725,19 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) · 2 unmodified lines | ||
| 698 | 725 | */ |
| 699 | 726 | static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter) |
| 700 | 727 | { |
| 701 | − struct sk_buff *skb; | |
| 702 | 728 | struct pcie_service_card *card = adapter->card; |
| 703 | 729 | |
| 704 | − /* Allocate memory for sleep cookie */ | |
| 705 | − skb = dev_alloc_skb(sizeof(u32)); | |
| 706 | − if (!skb) { | |
| 707 | − dev_err(adapter->dev, | |
| 708 | − "Unable to allocate skb for sleep cookie!\n"); | |
| 730 | + card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32), | |
| 731 | + &card->sleep_cookie_pbase); | |
| 732 | + if (!card->sleep_cookie_vbase) { | |
| 733 | + dev_err(adapter->dev, "pci_alloc_consistent failed!\n"); | |
| 709 | 734 | return -ENOMEM; |
| 710 | 735 | } |
| 711 | − mwifiex_update_sk_buff_pa(skb); | |
| 712 | − skb_put(skb, sizeof(u32)); | |
| 713 | − | |
| 714 | 736 | /* Init val of Sleep Cookie */ |
| 715 | − *(u32 *)skb->data = FW_AWAKE_COOKIE; | |
| 737 | + *(u32 *)card->sleep_cookie_vbase = FW_AWAKE_COOKIE; | |
| 716 | 738 | |
| 717 | 739 | dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n", |
| 718 | − *((u32 *)skb->data)); | |
| 719 | − | |
| 720 | − /* Save the sleep cookie */ | |
| 721 | − card->sleep_cookie = skb; | |
| 740 | + *((u32 *)card->sleep_cookie_vbase)); | |
| 722 | 741 | |
| 723 | 742 | return 0; |
| 724 | 743 | } |
| @@ -735,24 +754,57 @@ static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter) · 10 unmodified lines | ||
| 735 | 754 | |
| 736 | 755 | card = adapter->card; |
| 737 | 756 | |
| 738 | − if (card && card->sleep_cookie) { | |
| 739 | − dev_kfree_skb_any(card->sleep_cookie); | |
| 740 | − card->sleep_cookie = NULL; | |
| 757 | + if (card && card->sleep_cookie_vbase) { | |
| 758 | + pci_free_consistent(card->dev, sizeof(u32), | |
| 759 | + card->sleep_cookie_vbase, | |
| 760 | + card->sleep_cookie_pbase); | |
| 761 | + card->sleep_cookie_vbase = NULL; | |
| 741 | 762 | } |
| 742 | 763 | |
| 743 | 764 | return 0; |
| 744 | 765 | } |
| 745 | 766 | |
| 767 | +/* This function flushes the TX buffer descriptor ring | |
| 768 | + * This function defined as handler is also called while cleaning TXRX | |
| 769 | + * during disconnect/ bss stop. | |
| 770 | + */ | |
| 771 | +static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter) | |
| 772 | +{ | |
| 773 | + struct pcie_service_card *card = adapter->card; | |
| 774 | + u32 rdptr; | |
| 775 | + | |
| 776 | + /* Read the TX ring read pointer set by firmware */ | |
| 777 | + if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { | |
| 778 | + dev_err(adapter->dev, | |
| 779 | + "Flush TXBD: failed to read REG_TXBD_RDPTR\n"); | |
| 780 | + return -1; | |
| 781 | + } | |
| 782 | + | |
| 783 | + if (!mwifiex_pcie_txbd_empty(card, rdptr)) { | |
| 784 | + card->txbd_flush = 1; | |
| 785 | + /* write pointer already set at last send | |
| 786 | + * send dnld-rdy intr again, wait for completion. | |
| 787 | + */ | |
| 788 | + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, | |
| 789 | + CPU_INTR_DNLD_RDY)) { | |
| 790 | + dev_err(adapter->dev, | |
| 791 | + "failed to assert dnld-rdy interrupt.\n"); | |
| 792 | + return -1; | |
| 793 | + } | |
| 794 | + } | |
| 795 | + return 0; | |
| 796 | +} | |
| 797 | + | |
| 746 | 798 | /* |
| 747 | − * This function sends data buffer to device | |
| 799 | + * This function unmaps and frees downloaded data buffer | |
| 748 | 800 | */ |
| 749 | −static int | |
| 750 | −mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |
| 801 | +static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter) | |
| 751 | 802 | { |
| 803 | + const u32 num_tx_buffs = MWIFIEX_MAX_TXRX_BD; | |
| 804 | + struct sk_buff *skb; | |
| 805 | + dma_addr_t buf_pa; | |
| 806 | + u32 wrdoneidx, rdptr, unmap_count = 0; | |
| 752 | 807 | struct pcie_service_card *card = adapter->card; |
| 753 | − u32 wrindx, rdptr; | |
| 754 | − phys_addr_t *buf_pa; | |
| 755 | − __le16 *tmp; | |
| 756 | 808 | |
| 757 | 809 | if (!mwifiex_pcie_ok_to_access_hw(adapter)) |
| 758 | 810 | mwifiex_pm_wakeup_card(adapter); |
| @@ -760,34 +812,112 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) · 1 unmodified line | ||
| 760 | 812 | /* Read the TX ring read pointer set by firmware */ |
| 761 | 813 | if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { |
| 762 | 814 | dev_err(adapter->dev, |
| 763 | − "SEND DATA: failed to read REG_TXBD_RDPTR\n"); | |
| 815 | + "SEND COMP: failed to read REG_TXBD_RDPTR\n"); | |
| 764 | 816 | return -1; |
| 765 | 817 | } |
| 766 | 818 | |
| 767 | − wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK; | |
| 819 | + dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n", | |
| 820 | + card->txbd_rdptr, rdptr); | |
| 768 | 821 | |
| 769 | − dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr, | |
| 770 | − card->txbd_wrptr); | |
| 771 | − if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) != | |
| 772 | − (rdptr & MWIFIEX_TXBD_MASK)) || | |
| 773 | − ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | |
| 774 | − (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { | |
| 775 | − struct sk_buff *skb_data; | |
| 822 | + /* free from previous txbd_rdptr to current txbd_rdptr */ | |
| 823 | + while (((card->txbd_rdptr & MWIFIEX_TXBD_MASK) != | |
| 824 | + (rdptr & MWIFIEX_TXBD_MASK)) || | |
| 825 | + ((card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | |
| 826 | + (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { | |
| 827 | + wrdoneidx = card->txbd_rdptr & MWIFIEX_TXBD_MASK; | |
| 828 | + | |
| 829 | + skb = card->tx_buf_list[wrdoneidx]; | |
| 830 | + if (skb) { | |
| 831 | + dev_dbg(adapter->dev, | |
| 832 | + "SEND COMP: Detach skb %p at txbd_rdidx=%d\n", | |
| 833 | + skb, wrdoneidx); | |
| 834 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 835 | + pci_unmap_single(card->dev, buf_pa, skb->len, | |
| 836 | + PCI_DMA_TODEVICE); | |
| 837 | + | |
| 838 | + unmap_count++; | |
| 839 | + | |
| 840 | + if (card->txbd_flush) | |
| 841 | + mwifiex_write_data_complete(adapter, skb, 0, | |
| 842 | + -1); | |
| 843 | + else | |
| 844 | + mwifiex_write_data_complete(adapter, skb, 0, 0); | |
| 845 | + } | |
| 846 | + | |
| 847 | + card->tx_buf_list[wrdoneidx] = NULL; | |
| 848 | + card->txbd_ring[wrdoneidx]->paddr = 0; | |
| 849 | + card->rxbd_ring[wrdoneidx]->len = 0; | |
| 850 | + card->rxbd_ring[wrdoneidx]->flags = 0; | |
| 851 | + card->txbd_rdptr++; | |
| 852 | + | |
| 853 | + if ((card->txbd_rdptr & MWIFIEX_TXBD_MASK) == num_tx_buffs) | |
| 854 | + card->txbd_rdptr = ((card->txbd_rdptr & | |
| 855 | + MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ | |
| 856 | + MWIFIEX_BD_FLAG_ROLLOVER_IND); | |
| 857 | + } | |
| 858 | + | |
| 859 | + if (unmap_count) | |
| 860 | + adapter->data_sent = false; | |
| 861 | + | |
| 862 | + if (card->txbd_flush) { | |
| 863 | + if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) == | |
| 864 | + (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) && | |
| 865 | + ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | |
| 866 | + (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) | |
| 867 | + card->txbd_flush = 0; | |
| 868 | + else | |
| 869 | + mwifiex_clean_pcie_ring_buf(adapter); | |
| 870 | + } | |
| 871 | + | |
| 872 | + return 0; | |
| 873 | +} | |
| 874 | + | |
| 875 | +/* This function sends data buffer to device. First 4 bytes of payload | |
| 876 | + * are filled with payload length and payload type. Then this payload | |
| 877 | + * is mapped to PCI device memory. Tx ring pointers are advanced accordingly. | |
| 878 | + * Download ready interrupt to FW is deffered if Tx ring is not full and | |
| 879 | + * additional payload can be accomodated. | |
| 880 | + */ | |
| 881 | +static int | |
| 882 | +mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, | |
| 883 | + struct mwifiex_tx_param *tx_param) | |
| 884 | +{ | |
| 885 | + struct pcie_service_card *card = adapter->card; | |
| 886 | + u32 wrindx; | |
| 887 | + int ret; | |
| 888 | + dma_addr_t buf_pa; | |
| 889 | + __le16 *tmp; | |
| 890 | + | |
| 891 | + if (!(skb->data && skb->len)) { | |
| 892 | + dev_err(adapter->dev, "%s(): invalid parameter <%p, %#x>\n", | |
| 893 | + __func__, skb->data, skb->len); | |
| 894 | + return -1; | |
| 895 | + } | |
| 896 | + | |
| 897 | + if (!mwifiex_pcie_ok_to_access_hw(adapter)) | |
| 898 | + mwifiex_pm_wakeup_card(adapter); | |
| 899 | + | |
| 900 | + dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", | |
| 901 | + card->txbd_rdptr, card->txbd_wrptr); | |
| 902 | + if (mwifiex_pcie_txbd_not_full(card)) { | |
| 776 | 903 | u8 *payload; |
| 777 | 904 | |
| 778 | 905 | adapter->data_sent = true; |
| 779 | − skb_data = card->tx_buf_list[wrindx]; | |
| 780 | − memcpy(skb_data->data, skb->data, skb->len); | |
| 781 | − payload = skb_data->data; | |
| 906 | + payload = skb->data; | |
| 782 | 907 | tmp = (__le16 *)&payload[0]; |
| 783 | 908 | *tmp = cpu_to_le16((u16)skb->len); |
| 784 | 909 | tmp = (__le16 *)&payload[2]; |
| 785 | 910 | *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA); |
| 786 | − skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len); | |
| 787 | − skb_trim(skb_data, skb->len); | |
| 788 | − buf_pa = MWIFIEX_SKB_PACB(skb_data); | |
| 789 | − card->txbd_ring[wrindx]->paddr = *buf_pa; | |
| 790 | − card->txbd_ring[wrindx]->len = (u16)skb_data->len; | |
| 911 | + | |
| 912 | + if (mwifiex_map_pci_memory(adapter, skb, skb->len , | |
| 913 | + PCI_DMA_TODEVICE)) | |
| 914 | + return -1; | |
| 915 | + | |
| 916 | + wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK; | |
| 917 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 918 | + card->tx_buf_list[wrindx] = skb; | |
| 919 | + card->txbd_ring[wrindx]->paddr = buf_pa; | |
| 920 | + card->txbd_ring[wrindx]->len = (u16)skb->len; | |
| 791 | 921 | card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC | |
| 792 | 922 | MWIFIEX_BD_FLAG_LAST_DESC; |
| 793 | 923 | |
| @@ -802,19 +932,28 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) · 8 unmodified lines | ||
| 802 | 932 | card->txbd_wrptr)) { |
| 803 | 933 | dev_err(adapter->dev, |
| 804 | 934 | "SEND DATA: failed to write REG_TXBD_WRPTR\n"); |
| 805 | − return 0; | |
| 935 | + ret = -1; | |
| 936 | + goto done_unmap; | |
| 806 | 937 | } |
| 807 | − | |
| 808 | − /* Send the TX ready interrupt */ | |
| 809 | − if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, | |
| 810 | − CPU_INTR_DNLD_RDY)) { | |
| 811 | − dev_err(adapter->dev, | |
| 812 | − "SEND DATA: failed to assert door-bell intr\n"); | |
| 813 | − return -1; | |
| 938 | + if ((mwifiex_pcie_txbd_not_full(card)) && | |
| 939 | + tx_param->next_pkt_len) { | |
| 940 | + /* have more packets and TxBD still can hold more */ | |
| 941 | + dev_dbg(adapter->dev, | |
| 942 | + "SEND DATA: delay dnld-rdy interrupt.\n"); | |
| 943 | + adapter->data_sent = false; | |
| 944 | + } else { | |
| 945 | + /* Send the TX ready interrupt */ | |
| 946 | + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, | |
| 947 | + CPU_INTR_DNLD_RDY)) { | |
| 948 | + dev_err(adapter->dev, | |
| 949 | + "SEND DATA: failed to assert dnld-rdy interrupt.\n"); | |
| 950 | + ret = -1; | |
| 951 | + goto done_unmap; | |
| 952 | + } | |
| 814 | 953 | } |
| 815 | 954 | dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: " |
| 816 | 955 | "%#x> and sent packet to firmware successfully\n", |
| 817 | − rdptr, card->txbd_wrptr); | |
| 956 | + card->txbd_rdptr, card->txbd_wrptr); | |
| 818 | 957 | } else { |
| 819 | 958 | dev_dbg(adapter->dev, |
| 820 | 959 | "info: TX Ring full, can't send packets to fw\n"); |
| @@ -827,7 +966,15 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) · 6 unmodified lines | ||
| 827 | 966 | return -EBUSY; |
| 828 | 967 | } |
| 829 | 968 | |
| 830 | − return 0; | |
| 969 | + return -EINPROGRESS; | |
| 970 | +done_unmap: | |
| 971 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 972 | + pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE); | |
| 973 | + card->tx_buf_list[wrindx] = NULL; | |
| 974 | + card->txbd_ring[wrindx]->paddr = 0; | |
| 975 | + card->txbd_ring[wrindx]->len = 0; | |
| 976 | + card->txbd_ring[wrindx]->flags = 0; | |
| 977 | + return ret; | |
| 831 | 978 | } |
| 832 | 979 | |
| 833 | 980 | /* |
| @@ -838,9 +985,13 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) · 4 unmodified lines | ||
| 838 | 985 | { |
| 839 | 986 | struct pcie_service_card *card = adapter->card; |
| 840 | 987 | u32 wrptr, rd_index; |
| 988 | + dma_addr_t buf_pa; | |
| 841 | 989 | int ret = 0; |
| 842 | 990 | struct sk_buff *skb_tmp = NULL; |
| 843 | 991 | |
| 992 | + if (!mwifiex_pcie_ok_to_access_hw(adapter)) | |
| 993 | + mwifiex_pm_wakeup_card(adapter); | |
| 994 | + | |
| 844 | 995 | /* Read the RX ring Write pointer set by firmware */ |
| 845 | 996 | if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { |
| 846 | 997 | dev_err(adapter->dev, |
| @@ -848,6 +999,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) · 1 unmodified line | ||
| 848 | 999 | ret = -1; |
| 849 | 1000 | goto done; |
| 850 | 1001 | } |
| 1002 | + card->rxbd_wrptr = wrptr; | |
| 851 | 1003 | |
| 852 | 1004 | while (((wrptr & MWIFIEX_RXBD_MASK) != |
| 853 | 1005 | (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) || |
| @@ -855,27 +1007,50 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) · 1 unmodified line | ||
| 855 | 1007 | (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { |
| 856 | 1008 | struct sk_buff *skb_data; |
| 857 | 1009 | u16 rx_len; |
| 1010 | + __le16 pkt_len; | |
| 858 | 1011 | |
| 859 | 1012 | rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK; |
| 860 | 1013 | skb_data = card->rx_buf_list[rd_index]; |
| 861 | 1014 | |
| 1015 | + MWIFIEX_SKB_PACB(skb_data, &buf_pa); | |
| 1016 | + pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE, | |
| 1017 | + PCI_DMA_FROMDEVICE); | |
| 1018 | + card->rx_buf_list[rd_index] = NULL; | |
| 1019 | + | |
| 862 | 1020 | /* Get data length from interface header - |
| 863 | − first byte is len, second byte is type */ | |
| 864 | − rx_len = *((u16 *)skb_data->data); | |
| 1021 | + * first 2 bytes for len, next 2 bytes is for type | |
| 1022 | + */ | |
| 1023 | + pkt_len = *((__le16 *)skb_data->data); | |
| 1024 | + rx_len = le16_to_cpu(pkt_len); | |
| 1025 | + skb_put(skb_data, rx_len); | |
| 865 | 1026 | dev_dbg(adapter->dev, |
| 866 | 1027 | "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", |
| 867 | 1028 | card->rxbd_rdptr, wrptr, rx_len); |
| 868 | − skb_tmp = dev_alloc_skb(rx_len); | |
| 1029 | + skb_pull(skb_data, INTF_HEADER_LEN); | |
| 1030 | + mwifiex_handle_rx_packet(adapter, skb_data); | |
| 1031 | + | |
| 1032 | + skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); | |
| 869 | 1033 | if (!skb_tmp) { |
| 870 | − dev_dbg(adapter->dev, | |
| 871 | − "info: Failed to alloc skb for RX\n"); | |
| 872 | − ret = -EBUSY; | |
| 873 | − goto done; | |
| 1034 | + dev_err(adapter->dev, | |
| 1035 | + "Unable to allocate skb.\n"); | |
| 1036 | + return -ENOMEM; | |
| 874 | 1037 | } |
| 875 | 1038 | |
| 876 | − skb_put(skb_tmp, rx_len); | |
| 1039 | + if (mwifiex_map_pci_memory(adapter, skb_tmp, | |
| 1040 | + MWIFIEX_RX_DATA_BUF_SIZE, | |
| 1041 | + PCI_DMA_FROMDEVICE)) | |
| 1042 | + return -1; | |
| 1043 | + | |
| 1044 | + MWIFIEX_SKB_PACB(skb_tmp, &buf_pa); | |
| 1045 | + | |
| 1046 | + dev_dbg(adapter->dev, | |
| 1047 | + "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n", | |
| 1048 | + skb_tmp, rd_index); | |
| 1049 | + card->rx_buf_list[rd_index] = skb_tmp; | |
| 1050 | + card->rxbd_ring[rd_index]->paddr = buf_pa; | |
| 1051 | + card->rxbd_ring[rd_index]->len = skb_tmp->len; | |
| 1052 | + card->rxbd_ring[rd_index]->flags = 0; | |
| 877 | 1053 | |
| 878 | − memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len); | |
| 879 | 1054 | if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) == |
| 880 | 1055 | MWIFIEX_MAX_TXRX_BD) { |
| 881 | 1056 | card->rxbd_rdptr = ((card->rxbd_rdptr & |
| @@ -903,12 +1078,10 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) · 21 unmodified lines | ||
| 903 | 1078 | } |
| 904 | 1079 | dev_dbg(adapter->dev, |
| 905 | 1080 | "info: RECV DATA: Rcvd packet from fw successfully\n"); |
| 906 | − mwifiex_handle_rx_packet(adapter, skb_tmp); | |
| 1081 | + card->rxbd_wrptr = wrptr; | |
| 907 | 1082 | } |
| 908 | 1083 | |
| 909 | 1084 | done: |
| 910 | − if (ret && skb_tmp) | |
| 911 | − dev_kfree_skb_any(skb_tmp); | |
| 912 | 1085 | return ret; |
| 913 | 1086 | } |
| 914 | 1087 | |
| @@ -918,32 +1091,41 @@ done: · 3 unmodified lines | ||
| 918 | 1091 | static int |
| 919 | 1092 | mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) |
| 920 | 1093 | { |
| 921 | − phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb); | |
| 1094 | + dma_addr_t buf_pa; | |
| 1095 | + struct pcie_service_card *card = adapter->card; | |
| 922 | 1096 | |
| 923 | − if (!(skb->data && skb->len && *buf_pa)) { | |
| 1097 | + if (!(skb->data && skb->len)) { | |
| 924 | 1098 | dev_err(adapter->dev, |
| 925 | − "Invalid parameter in %s <%p, %#x:%x, %x>\n", | |
| 926 | − __func__, skb->data, skb->len, | |
| 927 | − (u32)*buf_pa, (u32)((u64)*buf_pa >> 32)); | |
| 1099 | + "Invalid parameter in %s <%p. len %d>\n", | |
| 1100 | + __func__, skb->data, skb->len); | |
| 928 | 1101 | return -1; |
| 929 | 1102 | } |
| 930 | 1103 | |
| 1104 | + if (mwifiex_map_pci_memory(adapter, skb, skb->len , PCI_DMA_TODEVICE)) | |
| 1105 | + return -1; | |
| 1106 | + | |
| 1107 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 1108 | + | |
| 931 | 1109 | /* Write the lower 32bits of the physical address to scratch |
| 932 | 1110 | * register 0 */ |
| 933 | − if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) { | |
| 1111 | + if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)buf_pa)) { | |
| 934 | 1112 | dev_err(adapter->dev, |
| 935 | 1113 | "%s: failed to write download command to boot code.\n", |
| 936 | 1114 | __func__); |
| 1115 | + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, | |
| 1116 | + PCI_DMA_TODEVICE); | |
| 937 | 1117 | return -1; |
| 938 | 1118 | } |
| 939 | 1119 | |
| 940 | 1120 | /* Write the upper 32bits of the physical address to scratch |
| 941 | 1121 | * register 1 */ |
| 942 | 1122 | if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG, |
| 943 | − (u32)((u64)*buf_pa >> 32))) { | |
| 1123 | + (u32)((u64)buf_pa >> 32))) { | |
| 944 | 1124 | dev_err(adapter->dev, |
| 945 | 1125 | "%s: failed to write download command to boot code.\n", |
| 946 | 1126 | __func__); |
| 1127 | + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, | |
| 1128 | + PCI_DMA_TODEVICE); | |
| 947 | 1129 | return -1; |
| 948 | 1130 | } |
| 949 | 1131 | |
| @@ -952,6 +1134,8 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) · 2 unmodified lines | ||
| 952 | 1134 | dev_err(adapter->dev, |
| 953 | 1135 | "%s: failed to write command len to scratch reg 2\n", |
| 954 | 1136 | __func__); |
| 1137 | + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, | |
| 1138 | + PCI_DMA_TODEVICE); | |
| 955 | 1139 | return -1; |
| 956 | 1140 | } |
| 957 | 1141 | |
| @@ -960,22 +1144,39 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) · 2 unmodified lines | ||
| 960 | 1144 | CPU_INTR_DOOR_BELL)) { |
| 961 | 1145 | dev_err(adapter->dev, |
| 962 | 1146 | "%s: failed to assert door-bell intr\n", __func__); |
| 1147 | + pci_unmap_single(card->dev, buf_pa, | |
| 1148 | + MWIFIEX_UPLD_SIZE, PCI_DMA_TODEVICE); | |
| 963 | 1149 | return -1; |
| 964 | 1150 | } |
| 965 | 1151 | |
| 966 | 1152 | return 0; |
| 967 | 1153 | } |
| 968 | 1154 | |
| 969 | −/* | |
| 970 | − * This function downloads commands to the device | |
| 1155 | +/* This function init rx port in firmware which in turn enables to receive data | |
| 1156 | + * from device before transmitting any packet. | |
| 1157 | + */ | |
| 1158 | +static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) | |
| 1159 | +{ | |
| 1160 | + struct pcie_service_card *card = adapter->card; | |
| 1161 | + | |
| 1162 | + /* Write the RX ring read pointer in to REG_RXBD_RDPTR */ | |
| 1163 | + if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, card->rxbd_rdptr | 0)) { | |
| 1164 | + dev_err(adapter->dev, | |
| 1165 | + "RECV DATA: failed to write REG_RXBD_RDPTR\n"); | |
| 1166 | + return -1; | |
| 1167 | + } | |
| 1168 | + return 0; | |
| 1169 | +} | |
| 1170 | + | |
| 1171 | +/* This function downloads commands to the device | |
| 971 | 1172 | */ |
| 972 | 1173 | static int |
| 973 | 1174 | mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) |
| 974 | 1175 | { |
| 975 | 1176 | struct pcie_service_card *card = adapter->card; |
| 976 | 1177 | int ret = 0; |
| 977 | − phys_addr_t *cmd_buf_pa; | |
| 978 | − phys_addr_t *cmdrsp_buf_pa; | |
| 1178 | + dma_addr_t cmd_buf_pa, cmdrsp_buf_pa; | |
| 1179 | + u8 *payload = (u8 *)skb->data; | |
| 979 | 1180 | |
| 980 | 1181 | if (!(skb->data && skb->len)) { |
| 981 | 1182 | dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n", |
| @@ -990,17 +1191,18 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) · 8 unmodified lines | ||
| 990 | 1191 | return -EBUSY; |
| 991 | 1192 | } |
| 992 | 1193 | |
| 993 | − /* Make sure a command buffer is available */ | |
| 994 | − if (!card->cmd_buf) { | |
| 995 | − dev_err(adapter->dev, "Command buffer not available\n"); | |
| 996 | − return -EBUSY; | |
| 997 | − } | |
| 1194 | + if (!mwifiex_pcie_ok_to_access_hw(adapter)) | |
| 1195 | + mwifiex_pm_wakeup_card(adapter); | |
| 998 | 1196 | |
| 999 | 1197 | adapter->cmd_sent = true; |
| 1000 | − /* Copy the given skb in to DMA accessable shared buffer */ | |
| 1001 | − skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len); | |
| 1002 | − skb_trim(card->cmd_buf, skb->len); | |
| 1003 | − memcpy(card->cmd_buf->data, skb->data, skb->len); | |
| 1198 | + | |
| 1199 | + *(__le16 *)&payload[0] = cpu_to_le16((u16)skb->len); | |
| 1200 | + *(__le16 *)&payload[2] = cpu_to_le16(MWIFIEX_TYPE_CMD); | |
| 1201 | + | |
| 1202 | + if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE)) | |
| 1203 | + return -1; | |
| 1204 | + | |
| 1205 | + card->cmd_buf = skb; | |
| 1004 | 1206 | |
| 1005 | 1207 | /* To send a command, the driver will: |
| 1006 | 1208 | 1. Write the 64bit physical address of the data buffer to |
| @@ -1013,11 +1215,11 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) · 6 unmodified lines | ||
| 1013 | 1215 | */ |
| 1014 | 1216 | |
| 1015 | 1217 | if (card->cmdrsp_buf) { |
| 1016 | − cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf); | |
| 1218 | + MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa); | |
| 1017 | 1219 | /* Write the lower 32bits of the cmdrsp buffer physical |
| 1018 | 1220 | address */ |
| 1019 | 1221 | if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, |
| 1020 | − (u32)*cmdrsp_buf_pa)) { | |
| 1222 | + (u32)cmdrsp_buf_pa)) { | |
| 1021 | 1223 | dev_err(adapter->dev, |
| 1022 | 1224 | "Failed to write download cmd to boot code.\n"); |
| 1023 | 1225 | ret = -1; |
| @@ -1026,7 +1228,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) · 2 unmodified lines | ||
| 1026 | 1228 | /* Write the upper 32bits of the cmdrsp buffer physical |
| 1027 | 1229 | address */ |
| 1028 | 1230 | if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, |
| 1029 | − (u32)((u64)*cmdrsp_buf_pa >> 32))) { | |
| 1231 | + (u32)((u64)cmdrsp_buf_pa >> 32))) { | |
| 1030 | 1232 | dev_err(adapter->dev, |
| 1031 | 1233 | "Failed to write download cmd to boot code.\n"); |
| 1032 | 1234 | ret = -1; |
| @@ -1034,9 +1236,9 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) · 1 unmodified line | ||
| 1034 | 1236 | } |
| 1035 | 1237 | } |
| 1036 | 1238 | |
| 1037 | − cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf); | |
| 1239 | + MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa); | |
| 1038 | 1240 | /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */ |
| 1039 | − if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)*cmd_buf_pa)) { | |
| 1241 | + if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)cmd_buf_pa)) { | |
| 1040 | 1242 | dev_err(adapter->dev, |
| 1041 | 1243 | "Failed to write download cmd to boot code.\n"); |
| 1042 | 1244 | ret = -1; |
| @@ -1044,7 +1246,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) · 1 unmodified line | ||
| 1044 | 1246 | } |
| 1045 | 1247 | /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */ |
| 1046 | 1248 | if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI, |
| 1047 | − (u32)((u64)*cmd_buf_pa >> 32))) { | |
| 1249 | + (u32)((u64)cmd_buf_pa >> 32))) { | |
| 1048 | 1250 | dev_err(adapter->dev, |
| 1049 | 1251 | "Failed to write download cmd to boot code.\n"); |
| 1050 | 1252 | ret = -1; |
| @@ -1083,11 +1285,22 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) · 32 unmodified lines | ||
| 1083 | 1285 | struct pcie_service_card *card = adapter->card; |
| 1084 | 1286 | struct sk_buff *skb = card->cmdrsp_buf; |
| 1085 | 1287 | int count = 0; |
| 1288 | + u16 rx_len; | |
| 1289 | + __le16 pkt_len; | |
| 1290 | + dma_addr_t buf_pa; | |
| 1086 | 1291 | |
| 1087 | 1292 | dev_dbg(adapter->dev, "info: Rx CMD Response\n"); |
| 1088 | 1293 | |
| 1294 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 1295 | + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, | |
| 1296 | + PCI_DMA_FROMDEVICE); | |
| 1297 | + | |
| 1298 | + pkt_len = *((__le16 *)skb->data); | |
| 1299 | + rx_len = le16_to_cpu(pkt_len); | |
| 1300 | + skb_trim(skb, rx_len); | |
| 1301 | + skb_pull(skb, INTF_HEADER_LEN); | |
| 1302 | + | |
| 1089 | 1303 | if (!adapter->curr_cmd) { |
| 1090 | − skb_pull(skb, INTF_HEADER_LEN); | |
| 1091 | 1304 | if (adapter->ps_state == PS_STATE_SLEEP_CFM) { |
| 1092 | 1305 | mwifiex_process_sleep_confirm_resp(adapter, skb->data, |
| 1093 | 1306 | skb->len); |
| @@ -1100,9 +1313,12 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) · 6 unmodified lines | ||
| 1100 | 1313 | } |
| 1101 | 1314 | memcpy(adapter->upld_buf, skb->data, |
| 1102 | 1315 | min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); |
| 1103 | − skb_push(skb, INTF_HEADER_LEN); | |
| 1316 | + if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, | |
| 1317 | + PCI_DMA_FROMDEVICE)) | |
| 1318 | + return -1; | |
| 1319 | + | |
| 1320 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 1104 | 1321 | } else if (mwifiex_pcie_ok_to_access_hw(adapter)) { |
| 1105 | − skb_pull(skb, INTF_HEADER_LEN); | |
| 1106 | 1322 | adapter->curr_cmd->resp_skb = skb; |
| 1107 | 1323 | adapter->cmd_resp_received = true; |
| 1108 | 1324 | /* Take the pointer and set it to CMD node and will |
| @@ -1136,10 +1352,23 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter, · 27 unmodified lines | ||
| 1136 | 1352 | struct sk_buff *skb) |
| 1137 | 1353 | { |
| 1138 | 1354 | struct pcie_service_card *card = adapter->card; |
| 1355 | + dma_addr_t buf_pa; | |
| 1356 | + struct sk_buff *skb_tmp; | |
| 1139 | 1357 | |
| 1140 | 1358 | if (skb) { |
| 1141 | 1359 | card->cmdrsp_buf = skb; |
| 1142 | 1360 | skb_push(card->cmdrsp_buf, INTF_HEADER_LEN); |
| 1361 | + if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, | |
| 1362 | + PCI_DMA_FROMDEVICE)) | |
| 1363 | + return -1; | |
| 1364 | + } | |
| 1365 | + | |
| 1366 | + skb_tmp = card->cmd_buf; | |
| 1367 | + if (skb_tmp) { | |
| 1368 | + MWIFIEX_SKB_PACB(skb_tmp, &buf_pa); | |
| 1369 | + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, | |
| 1370 | + PCI_DMA_FROMDEVICE); | |
| 1371 | + card->cmd_buf = NULL; | |
| 1143 | 1372 | } |
| 1144 | 1373 | |
| 1145 | 1374 | return 0; |
| @@ -1153,6 +1382,10 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) · 7 unmodified lines | ||
| 1153 | 1382 | struct pcie_service_card *card = adapter->card; |
| 1154 | 1383 | u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; |
| 1155 | 1384 | u32 wrptr, event; |
| 1385 | + dma_addr_t buf_pa; | |
| 1386 | + | |
| 1387 | + if (!mwifiex_pcie_ok_to_access_hw(adapter)) | |
| 1388 | + mwifiex_pm_wakeup_card(adapter); | |
| 1156 | 1389 | |
| 1157 | 1390 | if (adapter->event_received) { |
| 1158 | 1391 | dev_dbg(adapter->dev, "info: Event being processed, " |
| @@ -1184,6 +1417,10 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) · 25 unmodified lines | ||
| 1184 | 1417 | |
| 1185 | 1418 | dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr); |
| 1186 | 1419 | skb_cmd = card->evt_buf_list[rdptr]; |
| 1420 | + MWIFIEX_SKB_PACB(skb_cmd, &buf_pa); | |
| 1421 | + pci_unmap_single(card->dev, buf_pa, MAX_EVENT_SIZE, | |
| 1422 | + PCI_DMA_FROMDEVICE); | |
| 1423 | + | |
| 1187 | 1424 | /* Take the pointer and set it to event pointer in adapter |
| 1188 | 1425 | and will return back after event handling callback */ |
| 1189 | 1426 | card->evt_buf_list[rdptr] = NULL; |
| @@ -1228,7 +1465,7 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, · 38 unmodified lines | ||
| 1228 | 1465 | int ret = 0; |
| 1229 | 1466 | u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; |
| 1230 | 1467 | u32 wrptr; |
| 1231 | − phys_addr_t *buf_pa; | |
| 1468 | + dma_addr_t buf_pa; | |
| 1232 | 1469 | |
| 1233 | 1470 | if (!skb) |
| 1234 | 1471 | return 0; |
| @@ -1248,9 +1485,14 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, · 13 unmodified lines | ||
| 1248 | 1485 | |
| 1249 | 1486 | if (!card->evt_buf_list[rdptr]) { |
| 1250 | 1487 | skb_push(skb, INTF_HEADER_LEN); |
| 1488 | + if (mwifiex_map_pci_memory(adapter, skb, | |
| 1489 | + MAX_EVENT_SIZE, | |
| 1490 | + PCI_DMA_FROMDEVICE)) | |
| 1491 | + return -1; | |
| 1492 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 1251 | 1493 | card->evt_buf_list[rdptr] = skb; |
| 1252 | − buf_pa = MWIFIEX_SKB_PACB(skb); | |
| 1253 | − card->evtbd_ring[rdptr]->paddr = *buf_pa; | |
| 1494 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 1495 | + card->evtbd_ring[rdptr]->paddr = buf_pa; | |
| 1254 | 1496 | card->evtbd_ring[rdptr]->len = (u16)skb->len; |
| 1255 | 1497 | card->evtbd_ring[rdptr]->flags = 0; |
| 1256 | 1498 | skb = NULL; |
| @@ -1299,11 +1541,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, · 42 unmodified lines | ||
| 1299 | 1541 | struct sk_buff *skb; |
| 1300 | 1542 | u32 txlen, tx_blocks = 0, tries, len; |
| 1301 | 1543 | u32 block_retry_cnt = 0; |
| 1302 | − | |
| 1303 | − if (!adapter) { | |
| 1304 | − pr_err("adapter structure is not valid\n"); | |
| 1305 | − return -1; | |
| 1306 | − } | |
| 1544 | + dma_addr_t buf_pa; | |
| 1545 | + struct pcie_service_card *card = adapter->card; | |
| 1307 | 1546 | |
| 1308 | 1547 | if (!firmware || !firmware_len) { |
| 1309 | 1548 | dev_err(adapter->dev, |
| @@ -1325,7 +1564,6 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, · 15 unmodified lines | ||
| 1325 | 1564 | ret = -ENOMEM; |
| 1326 | 1565 | goto done; |
| 1327 | 1566 | } |
| 1328 | − mwifiex_update_sk_buff_pa(skb); | |
| 1329 | 1567 | |
| 1330 | 1568 | /* Perform firmware data transfer */ |
| 1331 | 1569 | do { |
| @@ -1400,6 +1638,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, · 68 unmodified lines | ||
| 1400 | 1638 | ret = -1; |
| 1401 | 1639 | goto done; |
| 1402 | 1640 | } |
| 1641 | + | |
| 1642 | + MWIFIEX_SKB_PACB(skb, &buf_pa); | |
| 1643 | + | |
| 1403 | 1644 | /* Wait for the command done interrupt */ |
| 1404 | 1645 | do { |
| 1405 | 1646 | if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS, |
| @@ -1407,11 +1648,17 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, · 1 unmodified line | ||
| 1407 | 1648 | dev_err(adapter->dev, "%s: Failed to read " |
| 1408 | 1649 | "interrupt status during fw dnld.\n", |
| 1409 | 1650 | __func__); |
| 1651 | + pci_unmap_single(card->dev, buf_pa, skb->len, | |
| 1652 | + PCI_DMA_TODEVICE); | |
| 1410 | 1653 | ret = -1; |
| 1411 | 1654 | goto done; |
| 1412 | 1655 | } |
| 1413 | 1656 | } while ((ireg_intr & CPU_INTR_DOOR_BELL) == |
| 1414 | 1657 | CPU_INTR_DOOR_BELL); |
| 1658 | + | |
| 1659 | + pci_unmap_single(card->dev, buf_pa, skb->len, | |
| 1660 | + PCI_DMA_TODEVICE); | |
| 1661 | + | |
| 1415 | 1662 | offset += txlen; |
| 1416 | 1663 | } while (true); |
| 1417 | 1664 | |
| @@ -1594,39 +1841,40 @@ exit: · 176 unmodified lines | ||
| 1594 | 1841 | static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) |
| 1595 | 1842 | { |
| 1596 | 1843 | int ret; |
| 1597 | − u32 pcie_ireg = 0; | |
| 1844 | + u32 pcie_ireg; | |
| 1598 | 1845 | unsigned long flags; |
| 1599 | 1846 | |
| 1600 | 1847 | spin_lock_irqsave(&adapter->int_lock, flags); |
| 1601 | 1848 | /* Clear out unused interrupts */ |
| 1602 | − adapter->int_status &= HOST_INTR_MASK; | |
| 1849 | + pcie_ireg = adapter->int_status; | |
| 1850 | + adapter->int_status = 0; | |
| 1603 | 1851 | spin_unlock_irqrestore(&adapter->int_lock, flags); |
| 1604 | 1852 | |
| 1605 | − while (adapter->int_status & HOST_INTR_MASK) { | |
| 1606 | − if (adapter->int_status & HOST_INTR_DNLD_DONE) { | |
| 1607 | − adapter->int_status &= ~HOST_INTR_DNLD_DONE; | |
| 1608 | − if (adapter->data_sent) { | |
| 1609 | − dev_dbg(adapter->dev, "info: DATA sent intr\n"); | |
| 1610 | − adapter->data_sent = false; | |
| 1611 | − } | |
| 1853 | + while (pcie_ireg & HOST_INTR_MASK) { | |
| 1854 | + if (pcie_ireg & HOST_INTR_DNLD_DONE) { | |
| 1855 | + pcie_ireg &= ~HOST_INTR_DNLD_DONE; | |
| 1856 | + dev_dbg(adapter->dev, "info: TX DNLD Done\n"); | |
| 1857 | + ret = mwifiex_pcie_send_data_complete(adapter); | |
| 1858 | + if (ret) | |
| 1859 | + return ret; | |
| 1612 | 1860 | } |
| 1613 | − if (adapter->int_status & HOST_INTR_UPLD_RDY) { | |
| 1614 | − adapter->int_status &= ~HOST_INTR_UPLD_RDY; | |
| 1861 | + if (pcie_ireg & HOST_INTR_UPLD_RDY) { | |
| 1862 | + pcie_ireg &= ~HOST_INTR_UPLD_RDY; | |
| 1615 | 1863 | dev_dbg(adapter->dev, "info: Rx DATA\n"); |
| 1616 | 1864 | ret = mwifiex_pcie_process_recv_data(adapter); |
| 1617 | 1865 | if (ret) |
| 1618 | 1866 | return ret; |
| 1619 | 1867 | } |
| 1620 | − if (adapter->int_status & HOST_INTR_EVENT_RDY) { | |
| 1621 | − adapter->int_status &= ~HOST_INTR_EVENT_RDY; | |
| 1868 | + if (pcie_ireg & HOST_INTR_EVENT_RDY) { | |
| 1869 | + pcie_ireg &= ~HOST_INTR_EVENT_RDY; | |
| 1622 | 1870 | dev_dbg(adapter->dev, "info: Rx EVENT\n"); |
| 1623 | 1871 | ret = mwifiex_pcie_process_event_ready(adapter); |
| 1624 | 1872 | if (ret) |
| 1625 | 1873 | return ret; |
| 1626 | 1874 | } |
| 1627 | 1875 | |
| 1628 | − if (adapter->int_status & HOST_INTR_CMD_DONE) { | |
| 1629 | − adapter->int_status &= ~HOST_INTR_CMD_DONE; | |
| 1876 | + if (pcie_ireg & HOST_INTR_CMD_DONE) { | |
| 1877 | + pcie_ireg &= ~HOST_INTR_CMD_DONE; | |
| 1630 | 1878 | if (adapter->cmd_sent) { |
| 1631 | 1879 | dev_dbg(adapter->dev, |
| 1632 | 1880 | "info: CMD sent Interrupt\n"); |
| @@ -1654,8 +1902,6 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) · 21 unmodified lines | ||
| 1654 | 1902 | "Write register failed\n"); |
| 1655 | 1903 | return -1; |
| 1656 | 1904 | } |
| 1657 | − adapter->int_status |= pcie_ireg; | |
| 1658 | − adapter->int_status &= HOST_INTR_MASK; | |
| 1659 | 1905 | } |
| 1660 | 1906 | |
| 1661 | 1907 | } |
| @@ -1687,7 +1933,7 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type, · 25 unmodified lines | ||
| 1687 | 1933 | } |
| 1688 | 1934 | |
| 1689 | 1935 | if (type == MWIFIEX_TYPE_DATA) |
| 1690 | − return mwifiex_pcie_send_data(adapter, skb); | |
| 1936 | + return mwifiex_pcie_send_data(adapter, skb, tx_param); | |
| 1691 | 1937 | else if (type == MWIFIEX_TYPE_CMD) |
| 1692 | 1938 | return mwifiex_pcie_send_cmd(adapter, skb); |
| 1693 | 1939 | |
| @@ -1814,15 +2060,8 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) · 120 unmodified lines | ||
| 1814 | 2060 | struct pcie_service_card *card = adapter->card; |
| 1815 | 2061 | struct pci_dev *pdev = card->dev; |
| 1816 | 2062 | |
| 1817 | − mwifiex_pcie_delete_sleep_cookie_buf(adapter); | |
| 1818 | − mwifiex_pcie_delete_cmdrsp_buf(adapter); | |
| 1819 | − mwifiex_pcie_delete_evtbd_ring(adapter); | |
| 1820 | − mwifiex_pcie_delete_rxbd_ring(adapter); | |
| 1821 | − mwifiex_pcie_delete_txbd_ring(adapter); | |
| 1822 | − card->cmdrsp_buf = NULL; | |
| 1823 | − | |
| 1824 | − dev_dbg(adapter->dev, "Clearing driver ready signature\n"); | |
| 1825 | 2063 | if (user_rmmod) { |
| 2064 | + dev_dbg(adapter->dev, "Clearing driver ready signature\n"); | |
| 1826 | 2065 | if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000)) |
| 1827 | 2066 | dev_err(adapter->dev, |
| 1828 | 2067 | "Failed to write driver not-ready signature\n"); |
| @@ -1879,6 +2118,13 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) · 50 unmodified lines | ||
| 1879 | 2118 | if (card) { |
| 1880 | 2119 | dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__); |
| 1881 | 2120 | free_irq(card->dev->irq, card->dev); |
| 2121 | + | |
| 2122 | + mwifiex_pcie_delete_sleep_cookie_buf(adapter); | |
| 2123 | + mwifiex_pcie_delete_cmdrsp_buf(adapter); | |
| 2124 | + mwifiex_pcie_delete_evtbd_ring(adapter); | |
| 2125 | + mwifiex_pcie_delete_rxbd_ring(adapter); | |
| 2126 | + mwifiex_pcie_delete_txbd_ring(adapter); | |
| 2127 | + card->cmdrsp_buf = NULL; | |
| 1882 | 2128 | } |
| 1883 | 2129 | } |
| 1884 | 2130 | |
| @@ -1900,6 +2146,8 @@ static struct mwifiex_if_ops pcie_ops = { · 15 unmodified lines | ||
| 1900 | 2146 | .event_complete = mwifiex_pcie_event_complete, |
| 1901 | 2147 | .update_mp_end_port = NULL, |
| 1902 | 2148 | .cleanup_mpa_buf = NULL, |
| 2149 | + .init_fw_port = mwifiex_pcie_init_fw_port, | |
| 2150 | + .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, | |
| 1903 | 2151 | }; |
| 1904 | 2152 | |
| 1905 | 2153 | /* |
| @@ -114,11 +114,12 @@ struct pcie_service_card { · 113 unmodified lines | ||
| 114 | 114 | struct pci_dev *dev; |
| 115 | 115 | struct mwifiex_adapter *adapter; |
| 116 | 116 | |
| 117 | + u8 txbd_flush; | |
| 117 | 118 | u32 txbd_wrptr; |
| 118 | 119 | u32 txbd_rdptr; |
| 119 | 120 | u32 txbd_ring_size; |
| 120 | 121 | u8 *txbd_ring_vbase; |
| 121 | − phys_addr_t txbd_ring_pbase; | |
| 122 | + dma_addr_t txbd_ring_pbase; | |
| 122 | 123 | struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD]; |
| 123 | 124 | struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD]; |
| 124 | 125 | |
| @@ -126,7 +127,7 @@ struct pcie_service_card { · 1 unmodified line | ||
| 126 | 127 | u32 rxbd_rdptr; |
| 127 | 128 | u32 rxbd_ring_size; |
| 128 | 129 | u8 *rxbd_ring_vbase; |
| 129 | − phys_addr_t rxbd_ring_pbase; | |
| 130 | + dma_addr_t rxbd_ring_pbase; | |
| 130 | 131 | struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; |
| 131 | 132 | struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD]; |
| 132 | 133 | |
| @@ -134,15 +135,39 @@ struct pcie_service_card { · 1 unmodified line | ||
| 134 | 135 | u32 evtbd_rdptr; |
| 135 | 136 | u32 evtbd_ring_size; |
| 136 | 137 | u8 *evtbd_ring_vbase; |
| 137 | − phys_addr_t evtbd_ring_pbase; | |
| 138 | + dma_addr_t evtbd_ring_pbase; | |
| 138 | 139 | struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD]; |
| 139 | 140 | struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD]; |
| 140 | 141 | |
| 141 | 142 | struct sk_buff *cmd_buf; |
| 142 | 143 | struct sk_buff *cmdrsp_buf; |
| 143 | − struct sk_buff *sleep_cookie; | |
| 144 | + u8 *sleep_cookie_vbase; | |
| 145 | + dma_addr_t sleep_cookie_pbase; | |
| 144 | 146 | void __iomem *pci_mmap; |
| 145 | 147 | void __iomem *pci_mmap1; |
| 146 | 148 | }; |
| 147 | 149 | |
| 150 | +static inline int | |
| 151 | +mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) | |
| 152 | +{ | |
| 153 | + if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) == | |
| 154 | + (rdptr & MWIFIEX_TXBD_MASK)) && | |
| 155 | + ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | |
| 156 | + (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) | |
| 157 | + return 1; | |
| 158 | + | |
| 159 | + return 0; | |
| 160 | +} | |
| 161 | + | |
| 162 | +static inline int | |
| 163 | +mwifiex_pcie_txbd_not_full(struct pcie_service_card *card) | |
| 164 | +{ | |
| 165 | + if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) != | |
| 166 | + (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) || | |
| 167 | + ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | |
| 168 | + (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) | |
| 169 | + return 1; | |
| 170 | + | |
| 171 | + return 0; | |
| 172 | +} | |
| 148 | 173 | #endif /* _MWIFIEX_PCIE_H */ |
| @@ -931,7 +931,6 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv, · 930 unmodified lines | ||
| 931 | 931 | struct host_cmd_ds_pcie_details *host_spec = |
| 932 | 932 | &cmd->params.pcie_host_spec; |
| 933 | 933 | struct pcie_service_card *card = priv->adapter->card; |
| 934 | − phys_addr_t *buf_pa; | |
| 935 | 934 | |
| 936 | 935 | cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS); |
| 937 | 936 | cmd->size = cpu_to_le16(sizeof(struct |
| @@ -953,10 +952,11 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv, · 15 unmodified lines | ||
| 953 | 952 | host_spec->evtbd_addr_lo = (u32)(card->evtbd_ring_pbase); |
| 954 | 953 | host_spec->evtbd_addr_hi = (u32)(((u64)card->evtbd_ring_pbase)>>32); |
| 955 | 954 | host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD; |
| 956 | − if (card->sleep_cookie) { | |
| 957 | − buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie); | |
| 958 | − host_spec->sleep_cookie_addr_lo = (u32) *buf_pa; | |
| 959 | − host_spec->sleep_cookie_addr_hi = (u32) (((u64)*buf_pa) >> 32); | |
| 955 | + if (card->sleep_cookie_vbase) { | |
| 956 | + host_spec->sleep_cookie_addr_lo = | |
| 957 | + (u32)(card->sleep_cookie_pbase); | |
| 958 | + host_spec->sleep_cookie_addr_hi = | |
| 959 | + (u32)(((u64)(card->sleep_cookie_pbase)) >> 32); | |
| 960 | 960 | dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: 0x%x\n", |
| 961 | 961 | host_spec->sleep_cookie_addr_lo); |
| 962 | 962 | } |
| @@ -56,7 +56,6 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, · 55 unmodified lines | ||
| 56 | 56 | */ |
| 57 | 57 | int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) |
| 58 | 58 | { |
| 59 | − bool cancel_flag = false; | |
| 60 | 59 | int status; |
| 61 | 60 | struct cmd_ctrl_node *cmd_queued; |
| 62 | 61 | |
| @@ -70,14 +69,11 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) · 7 unmodified lines | ||
| 70 | 69 | atomic_inc(&adapter->cmd_pending); |
| 71 | 70 | |
| 72 | 71 | /* Wait for completion */ |
| 73 | − wait_event_interruptible(adapter->cmd_wait_q.wait, | |
| 74 | − *(cmd_queued->condition)); | |
| 75 | − if (!*(cmd_queued->condition)) | |
| 76 | − cancel_flag = true; | |
| 77 | − | |
| 78 | − if (cancel_flag) { | |
| 79 | − mwifiex_cancel_pending_ioctl(adapter); | |
| 80 | − dev_dbg(adapter->dev, "cmd cancel\n"); | |
| 72 | + status = wait_event_interruptible(adapter->cmd_wait_q.wait, | |
| 73 | + *(cmd_queued->condition)); | |
| 74 | + if (status) { | |
| 75 | + dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status); | |
| 76 | + return status; | |
| 81 | 77 | } |
| 82 | 78 | |
| 83 | 79 | status = adapter->cmd_wait_q.status; |
| @@ -287,6 +283,20 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, · 203 unmodified lines | ||
| 287 | 283 | if (ret) |
| 288 | 284 | goto done; |
| 289 | 285 | |
| 286 | + if (bss_desc) { | |
| 287 | + u8 config_bands = 0; | |
| 288 | + | |
| 289 | + if (mwifiex_band_to_radio_type((u8) bss_desc->bss_band) | |
| 290 | + == HostCmd_SCAN_RADIO_TYPE_BG) | |
| 291 | + config_bands = BAND_B | BAND_G | BAND_GN; | |
| 292 | + else | |
| 293 | + config_bands = BAND_A | BAND_AN; | |
| 294 | + | |
| 295 | + if (!((config_bands | adapter->fw_bands) & | |
| 296 | + ~adapter->fw_bands)) | |
| 297 | + adapter->config_bands = config_bands; | |
| 298 | + } | |
| 299 | + | |
| 290 | 300 | ret = mwifiex_check_network_compatibility(priv, bss_desc); |
| 291 | 301 | if (ret) |
| 292 | 302 | goto done; |
| @@ -496,8 +506,11 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) · 203 unmodified lines | ||
| 496 | 506 | return false; |
| 497 | 507 | } |
| 498 | 508 | |
| 499 | − wait_event_interruptible(adapter->hs_activate_wait_q, | |
| 500 | − adapter->hs_activate_wait_q_woken); | |
| 509 | + if (wait_event_interruptible(adapter->hs_activate_wait_q, | |
| 510 | + adapter->hs_activate_wait_q_woken)) { | |
| 511 | + dev_err(adapter->dev, "hs_activate_wait_q terminated\n"); | |
| 512 | + return false; | |
| 513 | + } | |
| 501 | 514 | |
| 502 | 515 | return true; |
| 503 | 516 | } |
| @@ -117,14 +117,16 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, · 116 unmodified lines | ||
| 117 | 117 | dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); |
| 118 | 118 | break; |
| 119 | 119 | case -1: |
| 120 | − adapter->data_sent = false; | |
| 120 | + if (adapter->iface_type != MWIFIEX_PCIE) | |
| 121 | + adapter->data_sent = false; | |
| 121 | 122 | dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", |
| 122 | 123 | ret); |
| 123 | 124 | adapter->dbg.num_tx_host_to_card_failure++; |
| 124 | 125 | mwifiex_write_data_complete(adapter, skb, 0, ret); |
| 125 | 126 | break; |
| 126 | 127 | case -EINPROGRESS: |
| 127 | − adapter->data_sent = false; | |
| 128 | + if (adapter->iface_type != MWIFIEX_PCIE) | |
| 129 | + adapter->data_sent = false; | |
| 128 | 130 | break; |
| 129 | 131 | case 0: |
| 130 | 132 | mwifiex_write_data_complete(adapter, skb, 0, ret); |
| @@ -219,6 +219,7 @@ void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config) · 218 unmodified lines | ||
| 219 | 219 | config->rts_threshold = 0x7FFF; |
| 220 | 220 | config->frag_threshold = 0x7FFF; |
| 221 | 221 | config->retry_limit = 0x7F; |
| 222 | + config->qos_info = 0xFF; | |
| 222 | 223 | } |
| 223 | 224 | |
| 224 | 225 | /* This function parses BSS related parameters from structure |
| @@ -297,6 +298,38 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size) · 72 unmodified lines | ||
| 297 | 298 | return; |
| 298 | 299 | } |
| 299 | 300 | |
| 301 | +/* This function parses WMM related parameters from cfg80211_ap_settings | |
| 302 | + * structure and updates bss_config structure. | |
| 303 | + */ | |
| 304 | +void | |
| 305 | +mwifiex_set_wmm_params(struct mwifiex_private *priv, | |
| 306 | + struct mwifiex_uap_bss_param *bss_cfg, | |
| 307 | + struct cfg80211_ap_settings *params) | |
| 308 | +{ | |
| 309 | + const u8 *vendor_ie; | |
| 310 | + struct ieee_types_header *wmm_ie; | |
| 311 | + u8 wmm_oui[] = {0x00, 0x50, 0xf2, 0x02}; | |
| 312 | + | |
| 313 | + vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, | |
| 314 | + WLAN_OUI_TYPE_MICROSOFT_WMM, | |
| 315 | + params->beacon.tail, | |
| 316 | + params->beacon.tail_len); | |
| 317 | + if (vendor_ie) { | |
| 318 | + wmm_ie = (struct ieee_types_header *)vendor_ie; | |
| 319 | + memcpy(&bss_cfg->wmm_info, wmm_ie + 1, | |
| 320 | + sizeof(bss_cfg->wmm_info)); | |
| 321 | + priv->wmm_enabled = 1; | |
| 322 | + } else { | |
| 323 | + memset(&bss_cfg->wmm_info, 0, sizeof(bss_cfg->wmm_info)); | |
| 324 | + memcpy(&bss_cfg->wmm_info.oui, wmm_oui, sizeof(wmm_oui)); | |
| 325 | + bss_cfg->wmm_info.subtype = MWIFIEX_WMM_SUBTYPE; | |
| 326 | + bss_cfg->wmm_info.version = MWIFIEX_WMM_VERSION; | |
| 327 | + priv->wmm_enabled = 0; | |
| 328 | + } | |
| 329 | + | |
| 330 | + bss_cfg->qos_info = 0x00; | |
| 331 | + return; | |
| 332 | +} | |
| 300 | 333 | /* This function parses BSS related parameters from structure |
| 301 | 334 | * and prepares TLVs specific to WEP encryption. |
| 302 | 335 | * These TLVs are appended to command buffer. |
| @@ -354,6 +387,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) · 51 unmodified lines | ||
| 354 | 387 | struct host_cmd_tlv_rates *tlv_rates; |
| 355 | 388 | struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer; |
| 356 | 389 | struct mwifiex_ie_types_htcap *htcap; |
| 390 | + struct mwifiex_ie_types_wmmcap *wmm_cap; | |
| 357 | 391 | struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; |
| 358 | 392 | int i; |
| 359 | 393 | u16 cmd_size = *param_size; |
| @@ -507,6 +541,16 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) · 147 unmodified lines | ||
| 507 | 541 | tlv += sizeof(struct mwifiex_ie_types_htcap); |
| 508 | 542 | } |
| 509 | 543 | |
| 544 | + if (bss_cfg->wmm_info.qos_info != 0xFF) { | |
| 545 | + wmm_cap = (struct mwifiex_ie_types_wmmcap *)tlv; | |
| 546 | + wmm_cap->header.type = cpu_to_le16(WLAN_EID_VENDOR_SPECIFIC); | |
| 547 | + wmm_cap->header.len = cpu_to_le16(sizeof(wmm_cap->wmm_info)); | |
| 548 | + memcpy(&wmm_cap->wmm_info, &bss_cfg->wmm_info, | |
| 549 | + sizeof(wmm_cap->wmm_info)); | |
| 550 | + cmd_size += sizeof(struct mwifiex_ie_types_wmmcap); | |
| 551 | + tlv += sizeof(struct mwifiex_ie_types_wmmcap); | |
| 552 | + } | |
| 553 | + | |
| 510 | 554 | if (bss_cfg->sta_ao_timer) { |
| 511 | 555 | ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv; |
| 512 | 556 | ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER); |
| @@ -786,21 +786,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) · 785 unmodified lines | ||
| 786 | 786 | return 0; |
| 787 | 787 | } |
| 788 | 788 | |
| 789 | −/* This function reads one block of firmware data. */ | |
| 790 | −static int mwifiex_get_fw_data(struct mwifiex_adapter *adapter, | |
| 791 | − u32 offset, u32 len, u8 *buf) | |
| 792 | −{ | |
| 793 | − if (!buf || !len) | |
| 794 | − return -1; | |
| 795 | − | |
| 796 | − if (offset + len > adapter->firmware->size) | |
| 797 | − return -1; | |
| 798 | − | |
| 799 | − memcpy(buf, adapter->firmware->data + offset, len); | |
| 800 | − | |
| 801 | − return 0; | |
| 802 | −} | |
| 803 | − | |
| 804 | 789 | static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, |
| 805 | 790 | struct mwifiex_fw_image *fw) |
| 806 | 791 | { |
| @@ -836,23 +821,14 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, · 29 unmodified lines | ||
| 836 | 821 | dlen = 0; |
| 837 | 822 | } else { |
| 838 | 823 | /* copy the header of the fw_data to get the length */ |
| 839 | − if (firmware) | |
| 840 | − memcpy(&fwdata->fw_hdr, &firmware[tlen], | |
| 841 | − sizeof(struct fw_header)); | |
| 842 | − else | |
| 843 | − mwifiex_get_fw_data(adapter, tlen, | |
| 844 | − sizeof(struct fw_header), | |
| 845 | − (u8 *)&fwdata->fw_hdr); | |
| 824 | + memcpy(&fwdata->fw_hdr, &firmware[tlen], | |
| 825 | + sizeof(struct fw_header)); | |
| 846 | 826 | |
| 847 | 827 | dlen = le32_to_cpu(fwdata->fw_hdr.data_len); |
| 848 | 828 | dnld_cmd = le32_to_cpu(fwdata->fw_hdr.dnld_cmd); |
| 849 | 829 | tlen += sizeof(struct fw_header); |
| 850 | 830 | |
| 851 | − if (firmware) | |
| 852 | − memcpy(fwdata->data, &firmware[tlen], dlen); | |
| 853 | − else | |
| 854 | − mwifiex_get_fw_data(adapter, tlen, dlen, | |
| 855 | − (u8 *)fwdata->data); | |
| 831 | + memcpy(fwdata->data, &firmware[tlen], dlen); | |
| 856 | 832 | |
| 857 | 833 | fwdata->seq_num = cpu_to_le32(fw_seqnum); |
| 858 | 834 | tlen += dlen; |
| @@ -22,16 +22,16 @@ · 21 unmodified lines | ||
| 22 | 22 | |
| 23 | 23 | static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) |
| 24 | 24 | { |
| 25 | − return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t)); | |
| 25 | + return (struct mwifiex_rxinfo *)(skb->cb + sizeof(dma_addr_t)); | |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) |
| 29 | 29 | { |
| 30 | − return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t)); | |
| 30 | + return (struct mwifiex_txinfo *)(skb->cb + sizeof(dma_addr_t)); | |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | −static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb) | |
| 33 | +static inline void MWIFIEX_SKB_PACB(struct sk_buff *skb, dma_addr_t *buf_pa) | |
| 34 | 34 | { |
| 35 | − return (phys_addr_t *)skb->cb; | |
| 35 | + memcpy(buf_pa, skb->cb, sizeof(dma_addr_t)); | |
| 36 | 36 | } |
| 37 | 37 | #endif /* !_MWIFIEX_UTIL_H_ */ |
| @@ -568,6 +568,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) · 567 unmodified lines | ||
| 568 | 568 | mwifiex_wmm_delete_all_ralist(priv); |
| 569 | 569 | memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); |
| 570 | 570 | |
| 571 | + if (priv->adapter->if_ops.clean_pcie_ring) | |
| 572 | + priv->adapter->if_ops.clean_pcie_ring(priv->adapter); | |
| 571 | 573 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); |
| 572 | 574 | } |
| 573 | 575 | |
| @@ -1206,13 +1208,15 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, · 632 unmodified lines | ||
| 1206 | 1208 | ra_list_flags); |
| 1207 | 1209 | break; |
| 1208 | 1210 | case -1: |
| 1209 | − adapter->data_sent = false; | |
| 1211 | + if (adapter->iface_type != MWIFIEX_PCIE) | |
| 1212 | + adapter->data_sent = false; | |
| 1210 | 1213 | dev_err(adapter->dev, "host_to_card failed: %#x\n", ret); |
| 1211 | 1214 | adapter->dbg.num_tx_host_to_card_failure++; |
| 1212 | 1215 | mwifiex_write_data_complete(adapter, skb, 0, ret); |
| 1213 | 1216 | break; |
| 1214 | 1217 | case -EINPROGRESS: |
| 1215 | − adapter->data_sent = false; | |
| 1218 | + if (adapter->iface_type != MWIFIEX_PCIE) | |
| 1219 | + adapter->data_sent = false; | |
| 1216 | 1220 | default: |
| 1217 | 1221 | break; |
| 1218 | 1222 | } |
| @@ -101,6 +101,18 @@ MODULE_PARM_DESC(ap_mode_default, · 100 unmodified lines | ||
| 101 | 101 | #define MWL8K_MAX_TX_QUEUES (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES) |
| 102 | 102 | #define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues) |
| 103 | 103 | |
| 104 | +/* txpriorities are mapped with hw queues. | |
| 105 | + * Each hw queue has a txpriority. | |
| 106 | + */ | |
| 107 | +#define TOTAL_HW_TX_QUEUES 8 | |
| 108 | + | |
| 109 | +/* Each HW queue can have one AMPDU stream. | |
| 110 | + * But, because one of the hw queue is reserved, | |
| 111 | + * maximum AMPDU queues that can be created are | |
| 112 | + * one short of total tx queues. | |
| 113 | + */ | |
| 114 | +#define MWL8K_NUM_AMPDU_STREAMS (TOTAL_HW_TX_QUEUES - 1) | |
| 115 | + | |
| 104 | 116 | struct rxd_ops { |
| 105 | 117 | int rxd_size; |
| 106 | 118 | void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr); |
| @@ -160,7 +172,6 @@ struct mwl8k_ampdu_stream { · 53 unmodified lines | ||
| 160 | 172 | u8 tid; |
| 161 | 173 | u8 state; |
| 162 | 174 | u8 idx; |
| 163 | − u8 txq_idx; /* index of this stream in priv->txq */ | |
| 164 | 175 | }; |
| 165 | 176 | |
| 166 | 177 | struct mwl8k_priv { |
| @@ -202,6 +213,8 @@ struct mwl8k_priv { · 35 unmodified lines | ||
| 202 | 213 | int fw_mutex_depth; |
| 203 | 214 | struct completion *hostcmd_wait; |
| 204 | 215 | |
| 216 | + atomic_t watchdog_event_pending; | |
| 217 | + | |
| 205 | 218 | /* lock held over TX and TX reap */ |
| 206 | 219 | spinlock_t tx_lock; |
| 207 | 220 | |
| @@ -1516,6 +1529,9 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) · 1308 unmodified lines | ||
| 1516 | 1529 | return -EBUSY; |
| 1517 | 1530 | } |
| 1518 | 1531 | |
| 1532 | + if (atomic_read(&priv->watchdog_event_pending)) | |
| 1533 | + return 0; | |
| 1534 | + | |
| 1519 | 1535 | /* |
| 1520 | 1536 | * The TX queues are stopped at this point, so this test |
| 1521 | 1537 | * doesn't need to take ->tx_lock. |
| @@ -1537,6 +1553,14 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) · 15 unmodified lines | ||
| 1537 | 1553 | spin_unlock_bh(&priv->tx_lock); |
| 1538 | 1554 | timeout = wait_for_completion_timeout(&tx_wait, |
| 1539 | 1555 | msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS)); |
| 1556 | + | |
| 1557 | + if (atomic_read(&priv->watchdog_event_pending)) { | |
| 1558 | + spin_lock_bh(&priv->tx_lock); | |
| 1559 | + priv->tx_wait = NULL; | |
| 1560 | + spin_unlock_bh(&priv->tx_lock); | |
| 1561 | + return 0; | |
| 1562 | + } | |
| 1563 | + | |
| 1540 | 1564 | spin_lock_bh(&priv->tx_lock); |
| 1541 | 1565 | |
| 1542 | 1566 | if (timeout) { |
| @@ -1564,6 +1588,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) · 21 unmodified lines | ||
| 1564 | 1588 | |
| 1565 | 1589 | rc = -ETIMEDOUT; |
| 1566 | 1590 | } |
| 1591 | + priv->tx_wait = NULL; | |
| 1567 | 1592 | spin_unlock_bh(&priv->tx_lock); |
| 1568 | 1593 | |
| 1569 | 1594 | return rc; |
| @@ -1734,14 +1759,13 @@ mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) · 164 unmodified lines | ||
| 1734 | 1759 | struct mwl8k_priv *priv = hw->priv; |
| 1735 | 1760 | int i; |
| 1736 | 1761 | |
| 1737 | − for (i = 0; i < priv->num_ampdu_queues; i++) { | |
| 1762 | + for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) { | |
| 1738 | 1763 | stream = &priv->ampdu[i]; |
| 1739 | 1764 | if (stream->state == AMPDU_NO_STREAM) { |
| 1740 | 1765 | stream->sta = sta; |
| 1741 | 1766 | stream->state = AMPDU_STREAM_NEW; |
| 1742 | 1767 | stream->tid = tid; |
| 1743 | 1768 | stream->idx = i; |
| 1744 | − stream->txq_idx = MWL8K_TX_WMM_QUEUES + i; | |
| 1745 | 1769 | wiphy_debug(hw->wiphy, "Added a new stream for %pM %d", |
| 1746 | 1770 | sta->addr, tid); |
| 1747 | 1771 | return stream; |
| @@ -1782,7 +1806,7 @@ mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) · 34 unmodified lines | ||
| 1782 | 1806 | struct mwl8k_priv *priv = hw->priv; |
| 1783 | 1807 | int i; |
| 1784 | 1808 | |
| 1785 | − for (i = 0 ; i < priv->num_ampdu_queues; i++) { | |
| 1809 | + for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) { | |
| 1786 | 1810 | struct mwl8k_ampdu_stream *stream; |
| 1787 | 1811 | stream = &priv->ampdu[i]; |
| 1788 | 1812 | if (stream->state == AMPDU_NO_STREAM) |
| @@ -1829,6 +1853,13 @@ static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid) · 40 unmodified lines | ||
| 1829 | 1853 | tx_stats->pkts++; |
| 1830 | 1854 | } |
| 1831 | 1855 | |
| 1856 | +/* The hardware ampdu queues start from 5. | |
| 1857 | + * txpriorities for ampdu queues are | |
| 1858 | + * 5 6 7 0 1 2 3 4 ie., queue 5 is highest | |
| 1859 | + * and queue 3 is lowest (queue 4 is reserved) | |
| 1860 | + */ | |
| 1861 | +#define BA_QUEUE 5 | |
| 1862 | + | |
| 1832 | 1863 | static void |
| 1833 | 1864 | mwl8k_txq_xmit(struct ieee80211_hw *hw, |
| 1834 | 1865 | int index, |
| @@ -1928,8 +1959,13 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, · 93 unmodified lines | ||
| 1928 | 1959 | stream = mwl8k_lookup_stream(hw, sta->addr, tid); |
| 1929 | 1960 | if (stream != NULL) { |
| 1930 | 1961 | if (stream->state == AMPDU_STREAM_ACTIVE) { |
| 1931 | − txpriority = stream->txq_idx; | |
| 1932 | − index = stream->txq_idx; | |
| 1962 | + WARN_ON(!(qos & MWL8K_QOS_ACK_POLICY_BLOCKACK)); | |
| 1963 | + txpriority = (BA_QUEUE + stream->idx) % | |
| 1964 | + TOTAL_HW_TX_QUEUES; | |
| 1965 | + if (stream->idx <= 1) | |
| 1966 | + index = stream->idx + | |
| 1967 | + MWL8K_TX_WMM_QUEUES; | |
| 1968 | + | |
| 1933 | 1969 | } else if (stream->state == AMPDU_STREAM_NEW) { |
| 1934 | 1970 | /* We get here if the driver sends us packets |
| 1935 | 1971 | * after we've initiated a stream, but before |
| @@ -1971,6 +2007,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, · 35 unmodified lines | ||
| 1971 | 2007 | } |
| 1972 | 2008 | } |
| 1973 | 2009 | spin_unlock(&priv->stream_lock); |
| 2010 | + } else { | |
| 2011 | + qos &= ~MWL8K_QOS_ACK_POLICY_MASK; | |
| 2012 | + qos |= MWL8K_QOS_ACK_POLICY_NORMAL; | |
| 1974 | 2013 | } |
| 1975 | 2014 | |
| 1976 | 2015 | dma = pci_map_single(priv->pdev, skb->data, |
| @@ -3578,7 +3617,11 @@ static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap) · 1601 unmodified lines | ||
| 3578 | 3617 | return rc; |
| 3579 | 3618 | } |
| 3580 | 3619 | |
| 3581 | −#define INVALID_BA 0xAA | |
| 3620 | +#define MWL8K_WMM_QUEUE_NUMBER 3 | |
| 3621 | + | |
| 3622 | +static void mwl8k_destroy_ba(struct ieee80211_hw *hw, | |
| 3623 | + u8 idx); | |
| 3624 | + | |
| 3582 | 3625 | static void mwl8k_watchdog_ba_events(struct work_struct *work) |
| 3583 | 3626 | { |
| 3584 | 3627 | int rc; |
| @@ -3586,24 +3629,41 @@ static void mwl8k_watchdog_ba_events(struct work_struct *work) · 1 unmodified line | ||
| 3586 | 3629 | struct mwl8k_ampdu_stream *streams; |
| 3587 | 3630 | struct mwl8k_priv *priv = |
| 3588 | 3631 | container_of(work, struct mwl8k_priv, watchdog_ba_handle); |
| 3632 | + struct ieee80211_hw *hw = priv->hw; | |
| 3633 | + int i; | |
| 3634 | + u32 status = 0; | |
| 3635 | + | |
| 3636 | + mwl8k_fw_lock(hw); | |
| 3589 | 3637 | |
| 3590 | 3638 | rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap); |
| 3591 | 3639 | if (rc) |
| 3592 | − return; | |
| 3640 | + goto done; | |
| 3593 | 3641 | |
| 3594 | − if (bitmap == INVALID_BA) | |
| 3595 | − return; | |
| 3642 | + spin_lock(&priv->stream_lock); | |
| 3596 | 3643 | |
| 3597 | 3644 | /* the bitmap is the hw queue number. Map it to the ampdu queue. */ |
| 3598 | − stream_index = bitmap - MWL8K_TX_WMM_QUEUES; | |
| 3599 | − | |
| 3600 | − BUG_ON(stream_index >= priv->num_ampdu_queues); | |
| 3601 | − | |
| 3602 | − streams = &priv->ampdu[stream_index]; | |
| 3603 | − | |
| 3604 | − if (streams->state == AMPDU_STREAM_ACTIVE) | |
| 3605 | − ieee80211_stop_tx_ba_session(streams->sta, streams->tid); | |
| 3645 | + for (i = 0; i < TOTAL_HW_TX_QUEUES; i++) { | |
| 3646 | + if (bitmap & (1 << i)) { | |
| 3647 | + stream_index = (i + MWL8K_WMM_QUEUE_NUMBER) % | |
| 3648 | + TOTAL_HW_TX_QUEUES; | |
| 3649 | + streams = &priv->ampdu[stream_index]; | |
| 3650 | + if (streams->state == AMPDU_STREAM_ACTIVE) { | |
| 3651 | + ieee80211_stop_tx_ba_session(streams->sta, | |
| 3652 | + streams->tid); | |
| 3653 | + spin_unlock(&priv->stream_lock); | |
| 3654 | + mwl8k_destroy_ba(hw, stream_index); | |
| 3655 | + spin_lock(&priv->stream_lock); | |
| 3656 | + } | |
| 3657 | + } | |
| 3658 | + } | |
| 3606 | 3659 | |
| 3660 | + spin_unlock(&priv->stream_lock); | |
| 3661 | +done: | |
| 3662 | + atomic_dec(&priv->watchdog_event_pending); | |
| 3663 | + status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | |
| 3664 | + iowrite32((status | MWL8K_A2H_INT_BA_WATCHDOG), | |
| 3665 | + priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | |
| 3666 | + mwl8k_fw_unlock(hw); | |
| 3607 | 3667 | return; |
| 3608 | 3668 | } |
| 3609 | 3669 | |
| @@ -3763,7 +3823,7 @@ mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, · 153 unmodified lines | ||
| 3763 | 3823 | } |
| 3764 | 3824 | |
| 3765 | 3825 | static void mwl8k_destroy_ba(struct ieee80211_hw *hw, |
| 3766 | − struct mwl8k_ampdu_stream *stream) | |
| 3826 | + u8 idx) | |
| 3767 | 3827 | { |
| 3768 | 3828 | struct mwl8k_cmd_bastream *cmd; |
| 3769 | 3829 | |
| @@ -3775,10 +3835,10 @@ static void mwl8k_destroy_ba(struct ieee80211_hw *hw, · 5 unmodified lines | ||
| 3775 | 3835 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
| 3776 | 3836 | cmd->action = cpu_to_le32(MWL8K_BA_DESTROY); |
| 3777 | 3837 | |
| 3778 | − cmd->destroy_params.ba_context = cpu_to_le32(stream->idx); | |
| 3838 | + cmd->destroy_params.ba_context = cpu_to_le32(idx); | |
| 3779 | 3839 | mwl8k_post_cmd(hw, &cmd->header); |
| 3780 | 3840 | |
| 3781 | − wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx); | |
| 3841 | + wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", idx); | |
| 3782 | 3842 | |
| 3783 | 3843 | kfree(cmd); |
| 3784 | 3844 | } |
| @@ -3875,7 +3935,30 @@ static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, · 90 unmodified lines | ||
| 3875 | 3935 | struct ieee80211_vif *vif, u8 *addr) |
| 3876 | 3936 | { |
| 3877 | 3937 | struct mwl8k_cmd_set_new_stn *cmd; |
| 3878 | − int rc; | |
| 3938 | + struct mwl8k_priv *priv = hw->priv; | |
| 3939 | + int rc, i; | |
| 3940 | + u8 idx; | |
| 3941 | + | |
| 3942 | + spin_lock(&priv->stream_lock); | |
| 3943 | + /* Destroy any active ampdu streams for this sta */ | |
| 3944 | + for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) { | |
| 3945 | + struct mwl8k_ampdu_stream *s; | |
| 3946 | + s = &priv->ampdu[i]; | |
| 3947 | + if (s->state != AMPDU_NO_STREAM) { | |
| 3948 | + if (memcmp(s->sta->addr, addr, ETH_ALEN) == 0) { | |
| 3949 | + if (s->state == AMPDU_STREAM_ACTIVE) { | |
| 3950 | + idx = s->idx; | |
| 3951 | + spin_unlock(&priv->stream_lock); | |
| 3952 | + mwl8k_destroy_ba(hw, idx); | |
| 3953 | + spin_lock(&priv->stream_lock); | |
| 3954 | + } else if (s->state == AMPDU_STREAM_NEW) { | |
| 3955 | + mwl8k_remove_stream(hw, s); | |
| 3956 | + } | |
| 3957 | + } | |
| 3958 | + } | |
| 3959 | + } | |
| 3960 | + | |
| 3961 | + spin_unlock(&priv->stream_lock); | |
| 3879 | 3962 | |
| 3880 | 3963 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
| 3881 | 3964 | if (cmd == NULL) |
| @@ -4250,9 +4333,11 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, · 368 unmodified lines | ||
| 4250 | 4333 | p->amsdu_enabled = 0; |
| 4251 | 4334 | |
| 4252 | 4335 | rc = mwl8k_post_cmd(hw, &cmd->header); |
| 4336 | + if (!rc) | |
| 4337 | + rc = p->station_id; | |
| 4253 | 4338 | kfree(cmd); |
| 4254 | 4339 | |
| 4255 | − return rc ? rc : p->station_id; | |
| 4340 | + return rc; | |
| 4256 | 4341 | } |
| 4257 | 4342 | |
| 4258 | 4343 | static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, |
| @@ -4301,6 +4386,10 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) · 42 unmodified lines | ||
| 4301 | 4386 | } |
| 4302 | 4387 | |
| 4303 | 4388 | if (status & MWL8K_A2H_INT_BA_WATCHDOG) { |
| 4389 | + iowrite32(~MWL8K_A2H_INT_BA_WATCHDOG, | |
| 4390 | + priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | |
| 4391 | + | |
| 4392 | + atomic_inc(&priv->watchdog_event_pending); | |
| 4304 | 4393 | status &= ~MWL8K_A2H_INT_BA_WATCHDOG; |
| 4305 | 4394 | ieee80211_queue_work(hw, &priv->watchdog_ba_handle); |
| 4306 | 4395 | } |
| @@ -4444,6 +4533,8 @@ static int mwl8k_start(struct ieee80211_hw *hw) · 137 unmodified lines | ||
| 4444 | 4533 | priv->irq = -1; |
| 4445 | 4534 | tasklet_disable(&priv->poll_tx_task); |
| 4446 | 4535 | tasklet_disable(&priv->poll_rx_task); |
| 4536 | + } else { | |
| 4537 | + ieee80211_wake_queues(hw); | |
| 4447 | 4538 | } |
| 4448 | 4539 | |
| 4449 | 4540 | return rc; |
| @@ -5092,7 +5183,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 642 unmodified lines | ||
| 5092 | 5183 | int i, rc = 0; |
| 5093 | 5184 | struct mwl8k_priv *priv = hw->priv; |
| 5094 | 5185 | struct mwl8k_ampdu_stream *stream; |
| 5095 | − u8 *addr = sta->addr; | |
| 5186 | + u8 *addr = sta->addr, idx; | |
| 5096 | 5187 | struct mwl8k_sta *sta_info = MWL8K_STA(sta); |
| 5097 | 5188 | |
| 5098 | 5189 | if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) |
| @@ -5175,8 +5266,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 76 unmodified lines | ||
| 5175 | 5266 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: |
| 5176 | 5267 | if (stream) { |
| 5177 | 5268 | if (stream->state == AMPDU_STREAM_ACTIVE) { |
| 5269 | + idx = stream->idx; | |
| 5178 | 5270 | spin_unlock(&priv->stream_lock); |
| 5179 | − mwl8k_destroy_ba(hw, stream); | |
| 5271 | + mwl8k_destroy_ba(hw, idx); | |
| 5180 | 5272 | spin_lock(&priv->stream_lock); |
| 5181 | 5273 | } |
| 5182 | 5274 | mwl8k_remove_stream(hw, stream); |
| @@ -5192,8 +5284,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 9 unmodified lines | ||
| 5192 | 5284 | if (!rc) |
| 5193 | 5285 | stream->state = AMPDU_STREAM_ACTIVE; |
| 5194 | 5286 | else { |
| 5287 | + idx = stream->idx; | |
| 5195 | 5288 | spin_unlock(&priv->stream_lock); |
| 5196 | − mwl8k_destroy_ba(hw, stream); | |
| 5289 | + mwl8k_destroy_ba(hw, idx); | |
| 5197 | 5290 | spin_lock(&priv->stream_lock); |
| 5198 | 5291 | wiphy_debug(hw->wiphy, |
| 5199 | 5292 | "Failed adding stream for sta %pM tid %d\n", |
| @@ -5256,7 +5349,7 @@ enum { · 56 unmodified lines | ||
| 5256 | 5349 | MWL8366, |
| 5257 | 5350 | }; |
| 5258 | 5351 | |
| 5259 | −#define MWL8K_8366_AP_FW_API 2 | |
| 5352 | +#define MWL8K_8366_AP_FW_API 3 | |
| 5260 | 5353 | #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" |
| 5261 | 5354 | #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) |
| 5262 | 5355 | |
| @@ -5464,6 +5557,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) · 201 unmodified lines | ||
| 5464 | 5557 | if (priv->rxd_ops == NULL) { |
| 5465 | 5558 | wiphy_err(hw->wiphy, |
| 5466 | 5559 | "Driver does not have AP firmware image support for this hardware\n"); |
| 5560 | + rc = -ENOENT; | |
| 5467 | 5561 | goto err_stop_firmware; |
| 5468 | 5562 | } |
| 5469 | 5563 | } else { |
| @@ -5473,6 +5567,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) · 3 unmodified lines | ||
| 5473 | 5567 | priv->sniffer_enabled = false; |
| 5474 | 5568 | priv->wmm_enabled = false; |
| 5475 | 5569 | priv->pending_tx_pkts = 0; |
| 5570 | + atomic_set(&priv->watchdog_event_pending, 0); | |
| 5476 | 5571 | |
| 5477 | 5572 | rc = mwl8k_rxq_init(hw, 0); |
| 5478 | 5573 | if (rc) |
| @@ -5809,6 +5904,7 @@ static int mwl8k_probe(struct pci_dev *pdev, · 330 unmodified lines | ||
| 5809 | 5904 | priv->sram = pci_iomap(pdev, 0, 0x10000); |
| 5810 | 5905 | if (priv->sram == NULL) { |
| 5811 | 5906 | wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); |
| 5907 | + rc = -EIO; | |
| 5812 | 5908 | goto err_iounmap; |
| 5813 | 5909 | } |
| 5814 | 5910 | |
| @@ -5821,6 +5917,7 @@ static int mwl8k_probe(struct pci_dev *pdev, · 6 unmodified lines | ||
| 5821 | 5917 | priv->regs = pci_iomap(pdev, 2, 0x10000); |
| 5822 | 5918 | if (priv->regs == NULL) { |
| 5823 | 5919 | wiphy_err(hw->wiphy, "Cannot map device registers\n"); |
| 5920 | + rc = -EIO; | |
| 5824 | 5921 | goto err_iounmap; |
| 5825 | 5922 | } |
| 5826 | 5923 | } |
| @@ -559,6 +559,7 @@ static int p54p_probe(struct pci_dev *pdev, · 558 unmodified lines | ||
| 559 | 559 | mem_len = pci_resource_len(pdev, 0); |
| 560 | 560 | if (mem_len < sizeof(struct p54p_csr)) { |
| 561 | 561 | dev_err(&pdev->dev, "Too short PCI resources\n"); |
| 562 | + err = -ENODEV; | |
| 562 | 563 | goto err_disable_dev; |
| 563 | 564 | } |
| 564 | 565 | |
| @@ -568,8 +569,10 @@ static int p54p_probe(struct pci_dev *pdev, · 3 unmodified lines | ||
| 568 | 569 | goto err_disable_dev; |
| 569 | 570 | } |
| 570 | 571 | |
| 571 | − if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) || | |
| 572 | − pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { | |
| 572 | + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | |
| 573 | + if (!err) | |
| 574 | + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | |
| 575 | + if (err) { | |
| 573 | 576 | dev_err(&pdev->dev, "No suitable DMA available\n"); |
| 574 | 577 | goto err_free_reg; |
| 575 | 578 | } |
| @@ -47,6 +47,7 @@ static struct usb_device_id p54u_table[] = { · 46 unmodified lines | ||
| 47 | 47 | {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */ |
| 48 | 48 | {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */ |
| 49 | 49 | {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ |
| 50 | + {USB_DEVICE(0x0675, 0x0530)}, /* DrayTek Vigor 530 */ | |
| 50 | 51 | {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */ |
| 51 | 52 | {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ |
| 52 | 53 | {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */ |
| @@ -82,6 +83,8 @@ static struct usb_device_id p54u_table[] = { · 29 unmodified lines | ||
| 82 | 83 | {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */ |
| 83 | 84 | {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ |
| 84 | 85 | {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ |
| 86 | + {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */ | |
| 87 | + {USB_DEVICE(0x083a, 0x4503)}, /* T-Com Sinus 154 data II */ | |
| 85 | 88 | {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ |
| 86 | 89 | {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */ |
| 87 | 90 | {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */ |
| @@ -101,6 +104,7 @@ static struct usb_device_id p54u_table[] = { · 13 unmodified lines | ||
| 101 | 104 | {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ |
| 102 | 105 | {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */ |
| 103 | 106 | {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ |
| 107 | + /* {USB_DEVICE(0x15a9, 0x0002)}, * Also SparkLAN WL-682 with 3887 */ | |
| 104 | 108 | {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */ |
| 105 | 109 | {USB_DEVICE(0x1740, 0x1000)}, /* Senao NUB-350 */ |
| 106 | 110 | {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ |
| @@ -1503,6 +1503,7 @@ static int prism54_get_auth(struct net_device *ndev, · 1502 unmodified lines | ||
| 1503 | 1503 | case DOT11_AUTH_BOTH: |
| 1504 | 1504 | case DOT11_AUTH_SK: |
| 1505 | 1505 | param->value = IW_AUTH_ALG_SHARED_KEY; |
| 1506 | + break; | |
| 1506 | 1507 | case DOT11_AUTH_NONE: |
| 1507 | 1508 | default: |
| 1508 | 1509 | param->value = 0; |
| @@ -1107,12 +1107,15 @@ static int ray_get_essid(struct net_device *dev, struct iw_request_info *info, · 1106 unmodified lines | ||
| 1107 | 1107 | union iwreq_data *wrqu, char *extra) |
| 1108 | 1108 | { |
| 1109 | 1109 | ray_dev_t *local = netdev_priv(dev); |
| 1110 | + UCHAR tmp[IW_ESSID_MAX_SIZE + 1]; | |
| 1110 | 1111 | |
| 1111 | 1112 | /* Get the essid that was set */ |
| 1112 | 1113 | memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); |
| 1114 | + memcpy(tmp, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); | |
| 1115 | + tmp[IW_ESSID_MAX_SIZE] = '\0'; | |
| 1113 | 1116 | |
| 1114 | 1117 | /* Push it out ! */ |
| 1115 | − wrqu->essid.length = strlen(extra); | |
| 1118 | + wrqu->essid.length = strlen(tmp); | |
| 1116 | 1119 | wrqu->essid.flags = 1; /* active */ |
| 1117 | 1120 | |
| 1118 | 1121 | return 0; |
| @@ -1842,6 +1845,8 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) · 723 unmodified lines | ||
| 1842 | 1845 | UCHAR tmp; |
| 1843 | 1846 | UCHAR cmd; |
| 1844 | 1847 | UCHAR status; |
| 1848 | + UCHAR memtmp[ESSID_SIZE + 1]; | |
| 1849 | + | |
| 1845 | 1850 | |
| 1846 | 1851 | if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */ |
| 1847 | 1852 | return IRQ_NONE; |
| @@ -1901,17 +1906,21 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) · 53 unmodified lines | ||
| 1901 | 1906 | break; |
| 1902 | 1907 | case CCS_START_NETWORK: |
| 1903 | 1908 | case CCS_JOIN_NETWORK: |
| 1909 | + memcpy(memtmp, local->sparm.b4.a_current_ess_id, | |
| 1910 | + ESSID_SIZE); | |
| 1911 | + memtmp[ESSID_SIZE] = '\0'; | |
| 1912 | + | |
| 1904 | 1913 | if (status == CCS_COMMAND_COMPLETE) { |
| 1905 | 1914 | if (readb |
| 1906 | 1915 | (&pccs->var.start_network.net_initiated) == |
| 1907 | 1916 | 1) { |
| 1908 | 1917 | dev_dbg(&link->dev, |
| 1909 | 1918 | "ray_cs interrupt network \"%s\" started\n", |
| 1910 | − local->sparm.b4.a_current_ess_id); | |
| 1919 | + memtmp); | |
| 1911 | 1920 | } else { |
| 1912 | 1921 | dev_dbg(&link->dev, |
| 1913 | 1922 | "ray_cs interrupt network \"%s\" joined\n", |
| 1914 | − local->sparm.b4.a_current_ess_id); | |
| 1923 | + memtmp); | |
| 1915 | 1924 | } |
| 1916 | 1925 | memcpy_fromio(&local->bss_id, |
| 1917 | 1926 | pccs->var.start_network.bssid, |
| @@ -1939,12 +1948,12 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) · 21 unmodified lines | ||
| 1939 | 1948 | if (status == CCS_START_NETWORK) { |
| 1940 | 1949 | dev_dbg(&link->dev, |
| 1941 | 1950 | "ray_cs interrupt network \"%s\" start failed\n", |
| 1942 | − local->sparm.b4.a_current_ess_id); | |
| 1951 | + memtmp); | |
| 1943 | 1952 | local->timer.function = start_net; |
| 1944 | 1953 | } else { |
| 1945 | 1954 | dev_dbg(&link->dev, |
| 1946 | 1955 | "ray_cs interrupt network \"%s\" join failed\n", |
| 1947 | − local->sparm.b4.a_current_ess_id); | |
| 1956 | + memtmp); | |
| 1948 | 1957 | local->timer.function = join_net; |
| 1949 | 1958 | } |
| 1950 | 1959 | add_timer(&local->timer); |
| @@ -1296,8 +1296,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, · 1295 unmodified lines | ||
| 1296 | 1296 | !(filter_flags & FIF_CONTROL)); |
| 1297 | 1297 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, |
| 1298 | 1298 | !(filter_flags & FIF_PSPOLL)); |
| 1299 | − rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, | |
| 1300 | − !(filter_flags & FIF_CONTROL)); | |
| 1299 | + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 0); | |
| 1301 | 1300 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, |
| 1302 | 1301 | !(filter_flags & FIF_CONTROL)); |
| 1303 | 1302 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, |
| @@ -3866,6 +3865,400 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, · 2562 unmodified lines | ||
| 3866 | 3865 | return rfcsr24; |
| 3867 | 3866 | } |
| 3868 | 3867 | |
| 3868 | +static void rt2800_init_rfcsr_305x_soc(struct rt2x00_dev *rt2x00dev) | |
| 3869 | +{ | |
| 3870 | + rt2800_rfcsr_write(rt2x00dev, 0, 0x50); | |
| 3871 | + rt2800_rfcsr_write(rt2x00dev, 1, 0x01); | |
| 3872 | + rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); | |
| 3873 | + rt2800_rfcsr_write(rt2x00dev, 3, 0x75); | |
| 3874 | + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); | |
| 3875 | + rt2800_rfcsr_write(rt2x00dev, 5, 0x03); | |
| 3876 | + rt2800_rfcsr_write(rt2x00dev, 6, 0x02); | |
| 3877 | + rt2800_rfcsr_write(rt2x00dev, 7, 0x50); | |
| 3878 | + rt2800_rfcsr_write(rt2x00dev, 8, 0x39); | |
| 3879 | + rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); | |
| 3880 | + rt2800_rfcsr_write(rt2x00dev, 10, 0x60); | |
| 3881 | + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); | |
| 3882 | + rt2800_rfcsr_write(rt2x00dev, 12, 0x75); | |
| 3883 | + rt2800_rfcsr_write(rt2x00dev, 13, 0x75); | |
| 3884 | + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); | |
| 3885 | + rt2800_rfcsr_write(rt2x00dev, 15, 0x58); | |
| 3886 | + rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); | |
| 3887 | + rt2800_rfcsr_write(rt2x00dev, 17, 0x92); | |
| 3888 | + rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); | |
| 3889 | + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); | |
| 3890 | + rt2800_rfcsr_write(rt2x00dev, 20, 0xba); | |
| 3891 | + rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); | |
| 3892 | + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); | |
| 3893 | + rt2800_rfcsr_write(rt2x00dev, 23, 0x31); | |
| 3894 | + rt2800_rfcsr_write(rt2x00dev, 24, 0x08); | |
| 3895 | + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); | |
| 3896 | + rt2800_rfcsr_write(rt2x00dev, 26, 0x25); | |
| 3897 | + rt2800_rfcsr_write(rt2x00dev, 27, 0x23); | |
| 3898 | + rt2800_rfcsr_write(rt2x00dev, 28, 0x13); | |
| 3899 | + rt2800_rfcsr_write(rt2x00dev, 29, 0x83); | |
| 3900 | + rt2800_rfcsr_write(rt2x00dev, 30, 0x00); | |
| 3901 | + rt2800_rfcsr_write(rt2x00dev, 31, 0x00); | |
| 3902 | +} | |
| 3903 | + | |
| 3904 | +static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) | |
| 3905 | +{ | |
| 3906 | + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); | |
| 3907 | + rt2800_rfcsr_write(rt2x00dev, 5, 0x03); | |
| 3908 | + rt2800_rfcsr_write(rt2x00dev, 6, 0x02); | |
| 3909 | + rt2800_rfcsr_write(rt2x00dev, 7, 0x60); | |
| 3910 | + rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); | |
| 3911 | + rt2800_rfcsr_write(rt2x00dev, 10, 0x41); | |
| 3912 | + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); | |
| 3913 | + rt2800_rfcsr_write(rt2x00dev, 12, 0x7b); | |
| 3914 | + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); | |
| 3915 | + rt2800_rfcsr_write(rt2x00dev, 15, 0x58); | |
| 3916 | + rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); | |
| 3917 | + rt2800_rfcsr_write(rt2x00dev, 17, 0x92); | |
| 3918 | + rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); | |
| 3919 | + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); | |
| 3920 | + rt2800_rfcsr_write(rt2x00dev, 20, 0xba); | |
| 3921 | + rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); | |
| 3922 | + rt2800_rfcsr_write(rt2x00dev, 24, 0x16); | |
| 3923 | + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); | |
| 3924 | + rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); | |
| 3925 | +} | |
| 3926 | + | |
| 3927 | +static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev) | |
| 3928 | +{ | |
| 3929 | + rt2800_rfcsr_write(rt2x00dev, 1, 0x0f); | |
| 3930 | + rt2800_rfcsr_write(rt2x00dev, 2, 0x80); | |
| 3931 | + rt2800_rfcsr_write(rt2x00dev, 3, 0x08); | |
| 3932 | + rt2800_rfcsr_write(rt2x00dev, 4, 0x00); | |
| 3933 | + rt2800_rfcsr_write(rt2x00dev, 6, 0xa0); | |
| 3934 | + rt2800_rfcsr_write(rt2x00dev, 8, 0xf3); | |
| 3935 | + rt2800_rfcsr_write(rt2x00dev, 9, 0x02); | |
| 3936 | + rt2800_rfcsr_write(rt2x00dev, 10, 0x53); | |
| 3937 | + rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); | |
| 3938 | + rt2800_rfcsr_write(rt2x00dev, 12, 0x46); | |
| 3939 | + rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); | |
| 3940 | + rt2800_rfcsr_write(rt2x00dev, 18, 0x02); | |
| 3941 | + rt2800_rfcsr_write(rt2x00dev, 22, 0x20); | |
| 3942 | + rt2800_rfcsr_write(rt2x00dev, 25, 0x83); | |
| 3943 | + rt2800_rfcsr_write(rt2x00dev, 26, 0x82); | |
| 3944 | + rt2800_rfcsr_write(rt2x00dev, 27, 0x09); | |
| 3945 | + rt2800_rfcsr_write(rt2x00dev, 29, 0x10); | |
| 3946 | + rt2800_rfcsr_write(rt2x00dev, 30, 0x10); | |
| 3947 | + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); | |
| 3948 | + rt2800_rfcsr_write(rt2x00dev, 32, 0x80); | |
| 3949 | + rt2800_rfcsr_write(rt2x00dev, 33, 0x00); | |
| 3950 | + rt2800_rfcsr_write(rt2x00dev, 34, 0x05); | |
| 3951 | + rt2800_rfcsr_write(rt2x00dev, 35, 0x12); | |
| 3952 | + rt2800_rfcsr_write(rt2x00dev, 36, 0x00); | |
| 3953 | + rt2800_rfcsr_write(rt2x00dev, 38, 0x85); | |
| 3954 | + rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); | |
| 3955 | + rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); | |
| 3956 | + rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); | |
| 3957 | + rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); | |
| 3958 | + rt2800_rfcsr_write(rt2x00dev, 43, 0x7b); | |
| 3959 | + rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); | |
| 3960 | + rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); | |
| 3961 | + rt2800_rfcsr_write(rt2x00dev, 46, 0x73); | |
| 3962 | + rt2800_rfcsr_write(rt2x00dev, 47, 0x00); | |
| 3963 | + rt2800_rfcsr_write(rt2x00dev, 48, 0x10); | |
| 3964 | + rt2800_rfcsr_write(rt2x00dev, 49, 0x98); | |
| 3965 | + rt2800_rfcsr_write(rt2x00dev, 52, 0x38); | |
| 3966 | + rt2800_rfcsr_write(rt2x00dev, 53, 0x00); | |
| 3967 | + rt2800_rfcsr_write(rt2x00dev, 54, 0x78); | |
| 3968 | + rt2800_rfcsr_write(rt2x00dev, 55, 0x43); | |
| 3969 | + rt2800_rfcsr_write(rt2x00dev, 56, 0x02); | |
| 3970 | + rt2800_rfcsr_write(rt2x00dev, 57, 0x80); | |
| 3971 | + rt2800_rfcsr_write(rt2x00dev, 58, 0x7f); | |
| 3972 | + rt2800_rfcsr_write(rt2x00dev, 59, 0x09); | |
| 3973 | + rt2800_rfcsr_write(rt2x00dev, 60, 0x45); | |
| 3974 | + rt2800_rfcsr_write(rt2x00dev, 61, 0xc1); | |
| 3975 | +} | |
| 3976 | + | |
| 3977 | +static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev) | |
| 3978 | +{ | |
| 3979 | + rt2800_rfcsr_write(rt2x00dev, 0, 0xf0); | |
| 3980 | + rt2800_rfcsr_write(rt2x00dev, 1, 0x23); | |
| 3981 | + rt2800_rfcsr_write(rt2x00dev, 2, 0x50); | |
| 3982 | + rt2800_rfcsr_write(rt2x00dev, 3, 0x18); | |
| 3983 | + rt2800_rfcsr_write(rt2x00dev, 4, 0x00); | |
| 3984 | + rt2800_rfcsr_write(rt2x00dev, 5, 0x00); | |
| 3985 | + rt2800_rfcsr_write(rt2x00dev, 6, 0x33); | |
| 3986 | + rt2800_rfcsr_write(rt2x00dev, 7, 0x00); | |
| 3987 | + rt2800_rfcsr_write(rt2x00dev, 8, 0xf1); | |
| 3988 | + rt2800_rfcsr_write(rt2x00dev, 9, 0x02); | |
| 3989 | + rt2800_rfcsr_write(rt2x00dev, 10, 0xd2); | |
| 3990 | + rt2800_rfcsr_write(rt2x00dev, 11, 0x42); | |
| 3991 | + rt2800_rfcsr_write(rt2x00dev, 12, 0x1c); | |
| 3992 | + rt2800_rfcsr_write(rt2x00dev, 13, 0x00); | |
| 3993 | + rt2800_rfcsr_write(rt2x00dev, 14, 0x5a); | |
| 3994 | + rt2800_rfcsr_write(rt2x00dev, 15, 0x00); | |
| 3995 | + rt2800_rfcsr_write(rt2x00dev, 16, 0x01); | |
| 3996 | + rt2800_rfcsr_write(rt2x00dev, 18, 0x45); | |
| 3997 | + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); | |
| 3998 | + rt2800_rfcsr_write(rt2x00dev, 20, 0x00); | |
| 3999 | + rt2800_rfcsr_write(rt2x00dev, 21, 0x00); | |
| 4000 | + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); | |
| 4001 | + rt2800_rfcsr_write(rt2x00dev, 23, 0x00); | |
| 4002 | + rt2800_rfcsr_write(rt2x00dev, 24, 0x00); | |
| 4003 | + rt2800_rfcsr_write(rt2x00dev, 25, 0x80); | |
| 4004 | + rt2800_rfcsr_write(rt2x00dev, 26, 0x00); | |
| 4005 | + rt2800_rfcsr_write(rt2x00dev, 27, 0x03); | |
| 4006 | + rt2800_rfcsr_write(rt2x00dev, 28, 0x03); | |
| 4007 | + rt2800_rfcsr_write(rt2x00dev, 29, 0x00); | |
| 4008 | + rt2800_rfcsr_write(rt2x00dev, 30, 0x10); | |
| 4009 | + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); | |
| 4010 | + rt2800_rfcsr_write(rt2x00dev, 32, 0x80); | |
| 4011 | + rt2800_rfcsr_write(rt2x00dev, 33, 0x00); | |
| 4012 | + rt2800_rfcsr_write(rt2x00dev, 34, 0x01); | |
| 4013 | + rt2800_rfcsr_write(rt2x00dev, 35, 0x03); | |
| 4014 | + rt2800_rfcsr_write(rt2x00dev, 36, 0xbd); | |
| 4015 | + rt2800_rfcsr_write(rt2x00dev, 37, 0x3c); | |
| 4016 | + rt2800_rfcsr_write(rt2x00dev, 38, 0x5f); | |
| 4017 | + rt2800_rfcsr_write(rt2x00dev, 39, 0xc5); | |
| 4018 | + rt2800_rfcsr_write(rt2x00dev, 40, 0x33); | |
| 4019 | + rt2800_rfcsr_write(rt2x00dev, 41, 0x5b); | |
| 4020 | + rt2800_rfcsr_write(rt2x00dev, 42, 0x5b); | |
| 4021 | + rt2800_rfcsr_write(rt2x00dev, 43, 0xdb); | |
| 4022 | + rt2800_rfcsr_write(rt2x00dev, 44, 0xdb); | |
| 4023 | + rt2800_rfcsr_write(rt2x00dev, 45, 0xdb); | |
| 4024 | + rt2800_rfcsr_write(rt2x00dev, 46, 0xdd); | |
| 4025 | + rt2800_rfcsr_write(rt2x00dev, 47, 0x0d); | |
| 4026 | + rt2800_rfcsr_write(rt2x00dev, 48, 0x14); | |
| 4027 | + rt2800_rfcsr_write(rt2x00dev, 49, 0x00); | |
| 4028 | + rt2800_rfcsr_write(rt2x00dev, 50, 0x2d); | |
| 4029 | + rt2800_rfcsr_write(rt2x00dev, 51, 0x7f); | |
| 4030 | + rt2800_rfcsr_write(rt2x00dev, 52, 0x00); | |
| 4031 | + rt2800_rfcsr_write(rt2x00dev, 53, 0x52); | |
| 4032 | + rt2800_rfcsr_write(rt2x00dev, 54, 0x1b); | |
| 4033 | + rt2800_rfcsr_write(rt2x00dev, 55, 0x7f); | |
| 4034 | + rt2800_rfcsr_write(rt2x00dev, 56, 0x00); | |
| 4035 | + rt2800_rfcsr_write(rt2x00dev, 57, 0x52); | |
| 4036 | + rt2800_rfcsr_write(rt2x00dev, 58, 0x1b); | |
| 4037 | + rt2800_rfcsr_write(rt2x00dev, 59, 0x00); | |
| 4038 | + rt2800_rfcsr_write(rt2x00dev, 60, 0x00); | |
| 4039 | + rt2800_rfcsr_write(rt2x00dev, 61, 0x00); | |
| 4040 | + rt2800_rfcsr_write(rt2x00dev, 62, 0x00); | |
| 4041 | + rt2800_rfcsr_write(rt2x00dev, 63, 0x00); | |
| 4042 | +} | |
| 4043 | + | |
| 4044 | +static void rt2800_init_rfcsr_3390(struct rt2x00_dev *rt2x00dev) | |
| 4045 | +{ | |
| 4046 | + rt2800_rfcsr_write(rt2x00dev, 0, 0xa0); | |
| 4047 | + rt2800_rfcsr_write(rt2x00dev, 1, 0xe1); | |
| 4048 | + rt2800_rfcsr_write(rt2x00dev, 2, 0xf1); | |
| 4049 | + rt2800_rfcsr_write(rt2x00dev, 3, 0x62); | |
| 4050 | + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); | |
| 4051 | + rt2800_rfcsr_write(rt2x00dev, 5, 0x8b); | |
| 4052 | + rt2800_rfcsr_write(rt2x00dev, 6, 0x42); | |
| 4053 | + rt2800_rfcsr_write(rt2x00dev, 7, 0x34); | |
| 4054 | + rt2800_rfcsr_write(rt2x00dev, 8, 0x00); | |
| 4055 | + rt2800_rfcsr_write(rt2x00dev, 9, 0xc0); | |
| 4056 | + rt2800_rfcsr_write(rt2x00dev, 10, 0x61); | |
| 4057 | + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); | |
| 4058 | + rt2800_rfcsr_write(rt2x00dev, 12, 0x3b); | |
| 4059 | + rt2800_rfcsr_write(rt2x00dev, 13, 0xe0); | |
| 4060 | + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); | |
| 4061 | + rt2800_rfcsr_write(rt2x00dev, 15, 0x53); | |
| 4062 | + rt2800_rfcsr_write(rt2x00dev, 16, 0xe0); | |
| 4063 | + rt2800_rfcsr_write(rt2x00dev, 17, 0x94); | |
| 4064 | + rt2800_rfcsr_write(rt2x00dev, 18, 0x5c); | |
| 4065 | + rt2800_rfcsr_write(rt2x00dev, 19, 0x4a); | |
| 4066 | + rt2800_rfcsr_write(rt2x00dev, 20, 0xb2); | |
| 4067 | + rt2800_rfcsr_write(rt2x00dev, 21, 0xf6); | |
| 4068 | + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); | |
| 4069 | + rt2800_rfcsr_write(rt2x00dev, 23, 0x14); | |
| 4070 | + rt2800_rfcsr_write(rt2x00dev, 24, 0x08); | |
| 4071 | + rt2800_rfcsr_write(rt2x00dev, 25, 0x3d); | |
| 4072 | + rt2800_rfcsr_write(rt2x00dev, 26, 0x85); | |
| 4073 | + rt2800_rfcsr_write(rt2x00dev, 27, 0x00); | |
| 4074 | + rt2800_rfcsr_write(rt2x00dev, 28, 0x41); | |
| 4075 | + rt2800_rfcsr_write(rt2x00dev, 29, 0x8f); | |
| 4076 | + rt2800_rfcsr_write(rt2x00dev, 30, 0x20); | |
| 4077 | + rt2800_rfcsr_write(rt2x00dev, 31, 0x0f); | |
| 4078 | +} | |
| 4079 | + | |
| 4080 | +static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev) | |
| 4081 | +{ | |
| 4082 | + rt2800_rfcsr_write(rt2x00dev, 0, 0x70); | |
| 4083 | + rt2800_rfcsr_write(rt2x00dev, 1, 0x81); | |
| 4084 | + rt2800_rfcsr_write(rt2x00dev, 2, 0xf1); | |
| 4085 | + rt2800_rfcsr_write(rt2x00dev, 3, 0x02); | |
| 4086 | + rt2800_rfcsr_write(rt2x00dev, 4, 0x4c); | |
| 4087 | + rt2800_rfcsr_write(rt2x00dev, 5, 0x05); | |
| 4088 | + rt2800_rfcsr_write(rt2x00dev, 6, 0x4a); | |
| 4089 | + rt2800_rfcsr_write(rt2x00dev, 7, 0xd8); | |
| 4090 | + rt2800_rfcsr_write(rt2x00dev, 9, 0xc3); | |
| 4091 | + rt2800_rfcsr_write(rt2x00dev, 10, 0xf1); | |
| 4092 | + rt2800_rfcsr_write(rt2x00dev, 11, 0xb9); | |
| 4093 | + rt2800_rfcsr_write(rt2x00dev, 12, 0x70); | |
| 4094 | + rt2800_rfcsr_write(rt2x00dev, 13, 0x65); | |
| 4095 | + rt2800_rfcsr_write(rt2x00dev, 14, 0xa0); | |
| 4096 | + rt2800_rfcsr_write(rt2x00dev, 15, 0x53); | |
| 4097 | + rt2800_rfcsr_write(rt2x00dev, 16, 0x4c); | |
| 4098 | + rt2800_rfcsr_write(rt2x00dev, 17, 0x23); | |
| 4099 | + rt2800_rfcsr_write(rt2x00dev, 18, 0xac); | |
| 4100 | + rt2800_rfcsr_write(rt2x00dev, 19, 0x93); | |
| 4101 | + rt2800_rfcsr_write(rt2x00dev, 20, 0xb3); | |
| 4102 | + rt2800_rfcsr_write(rt2x00dev, 21, 0xd0); | |
| 4103 | + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); | |
| 4104 | + rt2800_rfcsr_write(rt2x00dev, 23, 0x3c); | |
| 4105 | + rt2800_rfcsr_write(rt2x00dev, 24, 0x16); | |
| 4106 | + rt2800_rfcsr_write(rt2x00dev, 25, 0x15); | |
| 4107 | + rt2800_rfcsr_write(rt2x00dev, 26, 0x85); | |
| 4108 | + rt2800_rfcsr_write(rt2x00dev, 27, 0x00); | |
| 4109 | + rt2800_rfcsr_write(rt2x00dev, 28, 0x00); | |
| 4110 | + rt2800_rfcsr_write(rt2x00dev, 29, 0x9b); | |
| 4111 | + rt2800_rfcsr_write(rt2x00dev, 30, 0x09); | |
| 4112 | + rt2800_rfcsr_write(rt2x00dev, 31, 0x10); | |
| 4113 | +} | |
| 4114 | + | |
| 4115 | +static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev) | |
| 4116 | +{ | |
| 4117 | + rt2800_rfcsr_write(rt2x00dev, 1, 0x0f); | |
| 4118 | + rt2800_rfcsr_write(rt2x00dev, 2, 0x80); | |
| 4119 | + rt2800_rfcsr_write(rt2x00dev, 3, 0x88); | |
| 4120 | + rt2800_rfcsr_write(rt2x00dev, 5, 0x10); | |
| 4121 | + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4122 | + rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); | |
| 4123 | + else | |
| 4124 | + rt2800_rfcsr_write(rt2x00dev, 6, 0xa0); | |
| 4125 | + rt2800_rfcsr_write(rt2x00dev, 7, 0x00); | |
| 4126 | + rt2800_rfcsr_write(rt2x00dev, 10, 0x53); | |
| 4127 | + rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); | |
| 4128 | + rt2800_rfcsr_write(rt2x00dev, 12, 0xc6); | |
| 4129 | + rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); | |
| 4130 | + rt2800_rfcsr_write(rt2x00dev, 14, 0x00); | |
| 4131 | + rt2800_rfcsr_write(rt2x00dev, 15, 0x00); | |
| 4132 | + rt2800_rfcsr_write(rt2x00dev, 16, 0x00); | |
| 4133 | + rt2800_rfcsr_write(rt2x00dev, 18, 0x03); | |
| 4134 | + rt2800_rfcsr_write(rt2x00dev, 19, 0x00); | |
| 4135 | + | |
| 4136 | + rt2800_rfcsr_write(rt2x00dev, 20, 0x00); | |
| 4137 | + rt2800_rfcsr_write(rt2x00dev, 21, 0x00); | |
| 4138 | + rt2800_rfcsr_write(rt2x00dev, 22, 0x20); | |
| 4139 | + rt2800_rfcsr_write(rt2x00dev, 23, 0x00); | |
| 4140 | + rt2800_rfcsr_write(rt2x00dev, 24, 0x00); | |
| 4141 | + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4142 | + rt2800_rfcsr_write(rt2x00dev, 25, 0x80); | |
| 4143 | + else | |
| 4144 | + rt2800_rfcsr_write(rt2x00dev, 25, 0xc0); | |
| 4145 | + rt2800_rfcsr_write(rt2x00dev, 26, 0x00); | |
| 4146 | + rt2800_rfcsr_write(rt2x00dev, 27, 0x09); | |
| 4147 | + rt2800_rfcsr_write(rt2x00dev, 28, 0x00); | |
| 4148 | + rt2800_rfcsr_write(rt2x00dev, 29, 0x10); | |
| 4149 | + | |
| 4150 | + rt2800_rfcsr_write(rt2x00dev, 30, 0x00); | |
| 4151 | + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); | |
| 4152 | + rt2800_rfcsr_write(rt2x00dev, 32, 0x80); | |
| 4153 | + rt2800_rfcsr_write(rt2x00dev, 33, 0x00); | |
| 4154 | + rt2800_rfcsr_write(rt2x00dev, 34, 0x07); | |
| 4155 | + rt2800_rfcsr_write(rt2x00dev, 35, 0x12); | |
| 4156 | + rt2800_rfcsr_write(rt2x00dev, 36, 0x00); | |
| 4157 | + rt2800_rfcsr_write(rt2x00dev, 37, 0x08); | |
| 4158 | + rt2800_rfcsr_write(rt2x00dev, 38, 0x85); | |
| 4159 | + rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); | |
| 4160 | + | |
| 4161 | + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4162 | + rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); | |
| 4163 | + else | |
| 4164 | + rt2800_rfcsr_write(rt2x00dev, 40, 0x4b); | |
| 4165 | + rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); | |
| 4166 | + rt2800_rfcsr_write(rt2x00dev, 42, 0xd2); | |
| 4167 | + rt2800_rfcsr_write(rt2x00dev, 43, 0x9a); | |
| 4168 | + rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); | |
| 4169 | + rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); | |
| 4170 | + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4171 | + rt2800_rfcsr_write(rt2x00dev, 46, 0x73); | |
| 4172 | + else | |
| 4173 | + rt2800_rfcsr_write(rt2x00dev, 46, 0x7b); | |
| 4174 | + rt2800_rfcsr_write(rt2x00dev, 47, 0x00); | |
| 4175 | + rt2800_rfcsr_write(rt2x00dev, 48, 0x10); | |
| 4176 | + rt2800_rfcsr_write(rt2x00dev, 49, 0x94); | |
| 4177 | + | |
| 4178 | + rt2800_rfcsr_write(rt2x00dev, 52, 0x38); | |
| 4179 | + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4180 | + rt2800_rfcsr_write(rt2x00dev, 53, 0x00); | |
| 4181 | + else | |
| 4182 | + rt2800_rfcsr_write(rt2x00dev, 53, 0x84); | |
| 4183 | + rt2800_rfcsr_write(rt2x00dev, 54, 0x78); | |
| 4184 | + rt2800_rfcsr_write(rt2x00dev, 55, 0x44); | |
| 4185 | + rt2800_rfcsr_write(rt2x00dev, 56, 0x22); | |
| 4186 | + rt2800_rfcsr_write(rt2x00dev, 57, 0x80); | |
| 4187 | + rt2800_rfcsr_write(rt2x00dev, 58, 0x7f); | |
| 4188 | + rt2800_rfcsr_write(rt2x00dev, 59, 0x63); | |
| 4189 | + | |
| 4190 | + rt2800_rfcsr_write(rt2x00dev, 60, 0x45); | |
| 4191 | + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4192 | + rt2800_rfcsr_write(rt2x00dev, 61, 0xd1); | |
| 4193 | + else | |
| 4194 | + rt2800_rfcsr_write(rt2x00dev, 61, 0xdd); | |
| 4195 | + rt2800_rfcsr_write(rt2x00dev, 62, 0x00); | |
| 4196 | + rt2800_rfcsr_write(rt2x00dev, 63, 0x00); | |
| 4197 | +} | |
| 4198 | + | |
| 4199 | +static void rt2800_init_rfcsr_5392(struct rt2x00_dev *rt2x00dev) | |
| 4200 | +{ | |
| 4201 | + rt2800_rfcsr_write(rt2x00dev, 1, 0x17); | |
| 4202 | + rt2800_rfcsr_write(rt2x00dev, 2, 0x80); | |
| 4203 | + rt2800_rfcsr_write(rt2x00dev, 3, 0x88); | |
| 4204 | + rt2800_rfcsr_write(rt2x00dev, 5, 0x10); | |
| 4205 | + rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); | |
| 4206 | + rt2800_rfcsr_write(rt2x00dev, 7, 0x00); | |
| 4207 | + rt2800_rfcsr_write(rt2x00dev, 10, 0x53); | |
| 4208 | + rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); | |
| 4209 | + rt2800_rfcsr_write(rt2x00dev, 12, 0x46); | |
| 4210 | + rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); | |
| 4211 | + rt2800_rfcsr_write(rt2x00dev, 14, 0x00); | |
| 4212 | + rt2800_rfcsr_write(rt2x00dev, 15, 0x00); | |
| 4213 | + rt2800_rfcsr_write(rt2x00dev, 16, 0x00); | |
| 4214 | + rt2800_rfcsr_write(rt2x00dev, 18, 0x03); | |
| 4215 | + rt2800_rfcsr_write(rt2x00dev, 19, 0x4d); | |
| 4216 | + rt2800_rfcsr_write(rt2x00dev, 20, 0x00); | |
| 4217 | + rt2800_rfcsr_write(rt2x00dev, 21, 0x8d); | |
| 4218 | + rt2800_rfcsr_write(rt2x00dev, 22, 0x20); | |
| 4219 | + rt2800_rfcsr_write(rt2x00dev, 23, 0x0b); | |
| 4220 | + rt2800_rfcsr_write(rt2x00dev, 24, 0x44); | |
| 4221 | + rt2800_rfcsr_write(rt2x00dev, 25, 0x80); | |
| 4222 | + rt2800_rfcsr_write(rt2x00dev, 26, 0x82); | |
| 4223 | + rt2800_rfcsr_write(rt2x00dev, 27, 0x09); | |
| 4224 | + rt2800_rfcsr_write(rt2x00dev, 28, 0x00); | |
| 4225 | + rt2800_rfcsr_write(rt2x00dev, 29, 0x10); | |
| 4226 | + rt2800_rfcsr_write(rt2x00dev, 30, 0x10); | |
| 4227 | + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); | |
| 4228 | + rt2800_rfcsr_write(rt2x00dev, 32, 0x20); | |
| 4229 | + rt2800_rfcsr_write(rt2x00dev, 33, 0xC0); | |
| 4230 | + rt2800_rfcsr_write(rt2x00dev, 34, 0x07); | |
| 4231 | + rt2800_rfcsr_write(rt2x00dev, 35, 0x12); | |
| 4232 | + rt2800_rfcsr_write(rt2x00dev, 36, 0x00); | |
| 4233 | + rt2800_rfcsr_write(rt2x00dev, 37, 0x08); | |
| 4234 | + rt2800_rfcsr_write(rt2x00dev, 38, 0x89); | |
| 4235 | + rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); | |
| 4236 | + rt2800_rfcsr_write(rt2x00dev, 40, 0x0f); | |
| 4237 | + rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); | |
| 4238 | + rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); | |
| 4239 | + rt2800_rfcsr_write(rt2x00dev, 43, 0x9b); | |
| 4240 | + rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); | |
| 4241 | + rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); | |
| 4242 | + rt2800_rfcsr_write(rt2x00dev, 46, 0x73); | |
| 4243 | + rt2800_rfcsr_write(rt2x00dev, 47, 0x0c); | |
| 4244 | + rt2800_rfcsr_write(rt2x00dev, 48, 0x10); | |
| 4245 | + rt2800_rfcsr_write(rt2x00dev, 49, 0x94); | |
| 4246 | + rt2800_rfcsr_write(rt2x00dev, 50, 0x94); | |
| 4247 | + rt2800_rfcsr_write(rt2x00dev, 51, 0x3a); | |
| 4248 | + rt2800_rfcsr_write(rt2x00dev, 52, 0x48); | |
| 4249 | + rt2800_rfcsr_write(rt2x00dev, 53, 0x44); | |
| 4250 | + rt2800_rfcsr_write(rt2x00dev, 54, 0x38); | |
| 4251 | + rt2800_rfcsr_write(rt2x00dev, 55, 0x43); | |
| 4252 | + rt2800_rfcsr_write(rt2x00dev, 56, 0xa1); | |
| 4253 | + rt2800_rfcsr_write(rt2x00dev, 57, 0x00); | |
| 4254 | + rt2800_rfcsr_write(rt2x00dev, 58, 0x39); | |
| 4255 | + rt2800_rfcsr_write(rt2x00dev, 59, 0x07); | |
| 4256 | + rt2800_rfcsr_write(rt2x00dev, 60, 0x45); | |
| 4257 | + rt2800_rfcsr_write(rt2x00dev, 61, 0x91); | |
| 4258 | + rt2800_rfcsr_write(rt2x00dev, 62, 0x39); | |
| 4259 | + rt2800_rfcsr_write(rt2x00dev, 63, 0x07); | |
| 4260 | +} | |
| 4261 | + | |
| 3869 | 4262 | static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) |
| 3870 | 4263 | { |
| 3871 | 4264 | struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; |
| @@ -3889,6 +4282,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) · 17 unmodified lines | ||
| 3889 | 4282 | /* |
| 3890 | 4283 | * Init RF calibration. |
| 3891 | 4284 | */ |
| 4285 | + | |
| 3892 | 4286 | if (rt2x00_rt(rt2x00dev, RT3290) || |
| 3893 | 4287 | rt2x00_rt(rt2x00dev, RT5390) || |
| 3894 | 4288 | rt2x00_rt(rt2x00dev, RT5392)) { |
| @@ -3907,379 +4301,35 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) · 12 unmodified lines | ||
| 3907 | 4301 | rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); |
| 3908 | 4302 | } |
| 3909 | 4303 | |
| 3910 | − if (rt2x00_rt(rt2x00dev, RT3070) || | |
| 3911 | − rt2x00_rt(rt2x00dev, RT3071) || | |
| 3912 | − rt2x00_rt(rt2x00dev, RT3090)) { | |
| 3913 | − rt2800_rfcsr_write(rt2x00dev, 4, 0x40); | |
| 3914 | − rt2800_rfcsr_write(rt2x00dev, 5, 0x03); | |
| 3915 | − rt2800_rfcsr_write(rt2x00dev, 6, 0x02); | |
| 3916 | − rt2800_rfcsr_write(rt2x00dev, 7, 0x60); | |
| 3917 | − rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); | |
| 3918 | − rt2800_rfcsr_write(rt2x00dev, 10, 0x41); | |
| 3919 | − rt2800_rfcsr_write(rt2x00dev, 11, 0x21); | |
| 3920 | − rt2800_rfcsr_write(rt2x00dev, 12, 0x7b); | |
| 3921 | − rt2800_rfcsr_write(rt2x00dev, 14, 0x90); | |
| 3922 | − rt2800_rfcsr_write(rt2x00dev, 15, 0x58); | |
| 3923 | − rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); | |
| 3924 | − rt2800_rfcsr_write(rt2x00dev, 17, 0x92); | |
| 3925 | − rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); | |
| 3926 | − rt2800_rfcsr_write(rt2x00dev, 19, 0x02); | |
| 3927 | − rt2800_rfcsr_write(rt2x00dev, 20, 0xba); | |
| 3928 | − rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); | |
| 3929 | − rt2800_rfcsr_write(rt2x00dev, 24, 0x16); | |
| 3930 | − rt2800_rfcsr_write(rt2x00dev, 25, 0x01); | |
| 3931 | − rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); | |
| 3932 | − } else if (rt2x00_rt(rt2x00dev, RT3290)) { | |
| 3933 | − rt2800_rfcsr_write(rt2x00dev, 1, 0x0f); | |
| 3934 | − rt2800_rfcsr_write(rt2x00dev, 2, 0x80); | |
| 3935 | − rt2800_rfcsr_write(rt2x00dev, 3, 0x08); | |
| 3936 | − rt2800_rfcsr_write(rt2x00dev, 4, 0x00); | |
| 3937 | − rt2800_rfcsr_write(rt2x00dev, 6, 0xa0); | |
| 3938 | − rt2800_rfcsr_write(rt2x00dev, 8, 0xf3); | |
| 3939 | − rt2800_rfcsr_write(rt2x00dev, 9, 0x02); | |
| 3940 | − rt2800_rfcsr_write(rt2x00dev, 10, 0x53); | |
| 3941 | − rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); | |
| 3942 | − rt2800_rfcsr_write(rt2x00dev, 12, 0x46); | |
| 3943 | − rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); | |
| 3944 | − rt2800_rfcsr_write(rt2x00dev, 18, 0x02); | |
| 3945 | − rt2800_rfcsr_write(rt2x00dev, 22, 0x20); | |
| 3946 | − rt2800_rfcsr_write(rt2x00dev, 25, 0x83); | |
| 3947 | − rt2800_rfcsr_write(rt2x00dev, 26, 0x82); | |
| 3948 | − rt2800_rfcsr_write(rt2x00dev, 27, 0x09); | |
| 3949 | − rt2800_rfcsr_write(rt2x00dev, 29, 0x10); | |
| 3950 | − rt2800_rfcsr_write(rt2x00dev, 30, 0x10); | |
| 3951 | − rt2800_rfcsr_write(rt2x00dev, 31, 0x80); | |
| 3952 | − rt2800_rfcsr_write(rt2x00dev, 32, 0x80); | |
| 3953 | − rt2800_rfcsr_write(rt2x00dev, 33, 0x00); | |
| 3954 | − rt2800_rfcsr_write(rt2x00dev, 34, 0x05); | |
| 3955 | − rt2800_rfcsr_write(rt2x00dev, 35, 0x12); | |
| 3956 | − rt2800_rfcsr_write(rt2x00dev, 36, 0x00); | |
| 3957 | − rt2800_rfcsr_write(rt2x00dev, 38, 0x85); | |
| 3958 | − rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); | |
| 3959 | − rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); | |
| 3960 | − rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); | |
| 3961 | − rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); | |
| 3962 | − rt2800_rfcsr_write(rt2x00dev, 43, 0x7b); | |
| 3963 | − rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); | |
| 3964 | − rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); | |
| 3965 | − rt2800_rfcsr_write(rt2x00dev, 46, 0x73); | |
| 3966 | − rt2800_rfcsr_write(rt2x00dev, 47, 0x00); | |
| 3967 | − rt2800_rfcsr_write(rt2x00dev, 48, 0x10); | |
| 3968 | − rt2800_rfcsr_write(rt2x00dev, 49, 0x98); | |
| 3969 | − rt2800_rfcsr_write(rt2x00dev, 52, 0x38); | |
| 3970 | − rt2800_rfcsr_write(rt2x00dev, 53, 0x00); | |
| 3971 | − rt2800_rfcsr_write(rt2x00dev, 54, 0x78); | |
| 3972 | − rt2800_rfcsr_write(rt2x00dev, 55, 0x43); | |
| 3973 | − rt2800_rfcsr_write(rt2x00dev, 56, 0x02); | |
| 3974 | − rt2800_rfcsr_write(rt2x00dev, 57, 0x80); | |
| 3975 | − rt2800_rfcsr_write(rt2x00dev, 58, 0x7f); | |
| 3976 | − rt2800_rfcsr_write(rt2x00dev, 59, 0x09); | |
| 3977 | − rt2800_rfcsr_write(rt2x00dev, 60, 0x45); | |
| 3978 | − rt2800_rfcsr_write(rt2x00dev, 61, 0xc1); | |
| 3979 | − } else if (rt2x00_rt(rt2x00dev, RT3390)) { | |
| 3980 | − rt2800_rfcsr_write(rt2x00dev, 0, 0xa0); | |
| 3981 | − rt2800_rfcsr_write(rt2x00dev, 1, 0xe1); | |
| 3982 | − rt2800_rfcsr_write(rt2x00dev, 2, 0xf1); | |
| 3983 | − rt2800_rfcsr_write(rt2x00dev, 3, 0x62); | |
| 3984 | − rt2800_rfcsr_write(rt2x00dev, 4, 0x40); | |
| 3985 | − rt2800_rfcsr_write(rt2x00dev, 5, 0x8b); | |
| 3986 | − rt2800_rfcsr_write(rt2x00dev, 6, 0x42); | |
| 3987 | − rt2800_rfcsr_write(rt2x00dev, 7, 0x34); | |
| 3988 | − rt2800_rfcsr_write(rt2x00dev, 8, 0x00); | |
| 3989 | − rt2800_rfcsr_write(rt2x00dev, 9, 0xc0); | |
| 3990 | − rt2800_rfcsr_write(rt2x00dev, 10, 0x61); | |
| 3991 | − rt2800_rfcsr_write(rt2x00dev, 11, 0x21); | |
| 3992 | − rt2800_rfcsr_write(rt2x00dev, 12, 0x3b); | |
| 3993 | − rt2800_rfcsr_write(rt2x00dev, 13, 0xe0); | |
| 3994 | − rt2800_rfcsr_write(rt2x00dev, 14, 0x90); | |
| 3995 | − rt2800_rfcsr_write(rt2x00dev, 15, 0x53); | |
| 3996 | − rt2800_rfcsr_write(rt2x00dev, 16, 0xe0); | |
| 3997 | − rt2800_rfcsr_write(rt2x00dev, 17, 0x94); | |
| 3998 | − rt2800_rfcsr_write(rt2x00dev, 18, 0x5c); | |
| 3999 | − rt2800_rfcsr_write(rt2x00dev, 19, 0x4a); | |
| 4000 | − rt2800_rfcsr_write(rt2x00dev, 20, 0xb2); | |
| 4001 | − rt2800_rfcsr_write(rt2x00dev, 21, 0xf6); | |
| 4002 | − rt2800_rfcsr_write(rt2x00dev, 22, 0x00); | |
| 4003 | − rt2800_rfcsr_write(rt2x00dev, 23, 0x14); | |
| 4004 | − rt2800_rfcsr_write(rt2x00dev, 24, 0x08); | |
| 4005 | − rt2800_rfcsr_write(rt2x00dev, 25, 0x3d); | |
| 4006 | − rt2800_rfcsr_write(rt2x00dev, 26, 0x85); | |
| 4007 | − rt2800_rfcsr_write(rt2x00dev, 27, 0x00); | |
| 4008 | − rt2800_rfcsr_write(rt2x00dev, 28, 0x41); | |
| 4009 | − rt2800_rfcsr_write(rt2x00dev, 29, 0x8f); | |
| 4010 | − rt2800_rfcsr_write(rt2x00dev, 30, 0x20); | |
| 4011 | − rt2800_rfcsr_write(rt2x00dev, 31, 0x0f); | |
| 4012 | − } else if (rt2x00_rt(rt2x00dev, RT3572)) { | |
| 4013 | − rt2800_rfcsr_write(rt2x00dev, 0, 0x70); | |
| 4014 | − rt2800_rfcsr_write(rt2x00dev, 1, 0x81); | |
| 4015 | − rt2800_rfcsr_write(rt2x00dev, 2, 0xf1); | |
| 4016 | − rt2800_rfcsr_write(rt2x00dev, 3, 0x02); | |
| 4017 | − rt2800_rfcsr_write(rt2x00dev, 4, 0x4c); | |
| 4018 | − rt2800_rfcsr_write(rt2x00dev, 5, 0x05); | |
| 4019 | − rt2800_rfcsr_write(rt2x00dev, 6, 0x4a); | |
| 4020 | − rt2800_rfcsr_write(rt2x00dev, 7, 0xd8); | |
| 4021 | − rt2800_rfcsr_write(rt2x00dev, 9, 0xc3); | |
| 4022 | − rt2800_rfcsr_write(rt2x00dev, 10, 0xf1); | |
| 4023 | − rt2800_rfcsr_write(rt2x00dev, 11, 0xb9); | |
| 4024 | − rt2800_rfcsr_write(rt2x00dev, 12, 0x70); | |
| 4025 | − rt2800_rfcsr_write(rt2x00dev, 13, 0x65); | |
| 4026 | − rt2800_rfcsr_write(rt2x00dev, 14, 0xa0); | |
| 4027 | − rt2800_rfcsr_write(rt2x00dev, 15, 0x53); | |
| 4028 | − rt2800_rfcsr_write(rt2x00dev, 16, 0x4c); | |
| 4029 | − rt2800_rfcsr_write(rt2x00dev, 17, 0x23); | |
| 4030 | − rt2800_rfcsr_write(rt2x00dev, 18, 0xac); | |
| 4031 | − rt2800_rfcsr_write(rt2x00dev, 19, 0x93); | |
| 4032 | − rt2800_rfcsr_write(rt2x00dev, 20, 0xb3); | |
| 4033 | − rt2800_rfcsr_write(rt2x00dev, 21, 0xd0); | |
| 4034 | − rt2800_rfcsr_write(rt2x00dev, 22, 0x00); | |
| 4035 | − rt2800_rfcsr_write(rt2x00dev, 23, 0x3c); | |
| 4036 | − rt2800_rfcsr_write(rt2x00dev, 24, 0x16); | |
| 4037 | − rt2800_rfcsr_write(rt2x00dev, 25, 0x15); | |
| 4038 | − rt2800_rfcsr_write(rt2x00dev, 26, 0x85); | |
| 4039 | − rt2800_rfcsr_write(rt2x00dev, 27, 0x00); | |
| 4040 | − rt2800_rfcsr_write(rt2x00dev, 28, 0x00); | |
| 4041 | − rt2800_rfcsr_write(rt2x00dev, 29, 0x9b); | |
| 4042 | − rt2800_rfcsr_write(rt2x00dev, 30, 0x09); | |
| 4043 | − rt2800_rfcsr_write(rt2x00dev, 31, 0x10); | |
| 4044 | − } else if (rt2800_is_305x_soc(rt2x00dev)) { | |
| 4045 | − rt2800_rfcsr_write(rt2x00dev, 0, 0x50); | |
| 4046 | − rt2800_rfcsr_write(rt2x00dev, 1, 0x01); | |
| 4047 | − rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); | |
| 4048 | − rt2800_rfcsr_write(rt2x00dev, 3, 0x75); | |
| 4049 | − rt2800_rfcsr_write(rt2x00dev, 4, 0x40); | |
| 4050 | − rt2800_rfcsr_write(rt2x00dev, 5, 0x03); | |
| 4051 | − rt2800_rfcsr_write(rt2x00dev, 6, 0x02); | |
| 4052 | − rt2800_rfcsr_write(rt2x00dev, 7, 0x50); | |
| 4053 | − rt2800_rfcsr_write(rt2x00dev, 8, 0x39); | |
| 4054 | − rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); | |
| 4055 | − rt2800_rfcsr_write(rt2x00dev, 10, 0x60); | |
| 4056 | − rt2800_rfcsr_write(rt2x00dev, 11, 0x21); | |
| 4057 | − rt2800_rfcsr_write(rt2x00dev, 12, 0x75); | |
| 4058 | − rt2800_rfcsr_write(rt2x00dev, 13, 0x75); | |
| 4059 | − rt2800_rfcsr_write(rt2x00dev, 14, 0x90); | |
| 4060 | − rt2800_rfcsr_write(rt2x00dev, 15, 0x58); | |
| 4061 | − rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); | |
| 4062 | − rt2800_rfcsr_write(rt2x00dev, 17, 0x92); | |
| 4063 | − rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); | |
| 4064 | − rt2800_rfcsr_write(rt2x00dev, 19, 0x02); | |
| 4065 | − rt2800_rfcsr_write(rt2x00dev, 20, 0xba); | |
| 4066 | − rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); | |
| 4067 | − rt2800_rfcsr_write(rt2x00dev, 22, 0x00); | |
| 4068 | − rt2800_rfcsr_write(rt2x00dev, 23, 0x31); | |
| 4069 | − rt2800_rfcsr_write(rt2x00dev, 24, 0x08); | |
| 4070 | − rt2800_rfcsr_write(rt2x00dev, 25, 0x01); | |
| 4071 | − rt2800_rfcsr_write(rt2x00dev, 26, 0x25); | |
| 4072 | − rt2800_rfcsr_write(rt2x00dev, 27, 0x23); | |
| 4073 | − rt2800_rfcsr_write(rt2x00dev, 28, 0x13); | |
| 4074 | − rt2800_rfcsr_write(rt2x00dev, 29, 0x83); | |
| 4075 | − rt2800_rfcsr_write(rt2x00dev, 30, 0x00); | |
| 4076 | − rt2800_rfcsr_write(rt2x00dev, 31, 0x00); | |
| 4304 | + if (rt2800_is_305x_soc(rt2x00dev)) { | |
| 4305 | + rt2800_init_rfcsr_305x_soc(rt2x00dev); | |
| 4077 | 4306 | return 0; |
| 4078 | − } else if (rt2x00_rt(rt2x00dev, RT3352)) { | |
| 4079 | − rt2800_rfcsr_write(rt2x00dev, 0, 0xf0); | |
| 4080 | − rt2800_rfcsr_write(rt2x00dev, 1, 0x23); | |
| 4081 | − rt2800_rfcsr_write(rt2x00dev, 2, 0x50); | |
| 4082 | − rt2800_rfcsr_write(rt2x00dev, 3, 0x18); | |
| 4083 | − rt2800_rfcsr_write(rt2x00dev, 4, 0x00); | |
| 4084 | − rt2800_rfcsr_write(rt2x00dev, 5, 0x00); | |
| 4085 | − rt2800_rfcsr_write(rt2x00dev, 6, 0x33); | |
| 4086 | − rt2800_rfcsr_write(rt2x00dev, 7, 0x00); | |
| 4087 | − rt2800_rfcsr_write(rt2x00dev, 8, 0xf1); | |
| 4088 | − rt2800_rfcsr_write(rt2x00dev, 9, 0x02); | |
| 4089 | − rt2800_rfcsr_write(rt2x00dev, 10, 0xd2); | |
| 4090 | − rt2800_rfcsr_write(rt2x00dev, 11, 0x42); | |
| 4091 | − rt2800_rfcsr_write(rt2x00dev, 12, 0x1c); | |
| 4092 | − rt2800_rfcsr_write(rt2x00dev, 13, 0x00); | |
| 4093 | − rt2800_rfcsr_write(rt2x00dev, 14, 0x5a); | |
| 4094 | − rt2800_rfcsr_write(rt2x00dev, 15, 0x00); | |
| 4095 | − rt2800_rfcsr_write(rt2x00dev, 16, 0x01); | |
| 4096 | − rt2800_rfcsr_write(rt2x00dev, 18, 0x45); | |
| 4097 | − rt2800_rfcsr_write(rt2x00dev, 19, 0x02); | |
| 4098 | − rt2800_rfcsr_write(rt2x00dev, 20, 0x00); | |
| 4099 | − rt2800_rfcsr_write(rt2x00dev, 21, 0x00); | |
| 4100 | − rt2800_rfcsr_write(rt2x00dev, 22, 0x00); | |
| 4101 | − rt2800_rfcsr_write(rt2x00dev, 23, 0x00); | |
| 4102 | − rt2800_rfcsr_write(rt2x00dev, 24, 0x00); | |
| 4103 | − rt2800_rfcsr_write(rt2x00dev, 25, 0x80); | |
| 4104 | − rt2800_rfcsr_write(rt2x00dev, 26, 0x00); | |
| 4105 | − rt2800_rfcsr_write(rt2x00dev, 27, 0x03); | |
| 4106 | − rt2800_rfcsr_write(rt2x00dev, 28, 0x03); | |
| 4107 | − rt2800_rfcsr_write(rt2x00dev, 29, 0x00); | |
| 4108 | − rt2800_rfcsr_write(rt2x00dev, 30, 0x10); | |
| 4109 | − rt2800_rfcsr_write(rt2x00dev, 31, 0x80); | |
| 4110 | − rt2800_rfcsr_write(rt2x00dev, 32, 0x80); | |
| 4111 | − rt2800_rfcsr_write(rt2x00dev, 33, 0x00); | |
| 4112 | − rt2800_rfcsr_write(rt2x00dev, 34, 0x01); | |
| 4113 | − rt2800_rfcsr_write(rt2x00dev, 35, 0x03); | |
| 4114 | − rt2800_rfcsr_write(rt2x00dev, 36, 0xbd); | |
| 4115 | − rt2800_rfcsr_write(rt2x00dev, 37, 0x3c); | |
| 4116 | − rt2800_rfcsr_write(rt2x00dev, 38, 0x5f); | |
| 4117 | − rt2800_rfcsr_write(rt2x00dev, 39, 0xc5); | |
| 4118 | − rt2800_rfcsr_write(rt2x00dev, 40, 0x33); | |
| 4119 | − rt2800_rfcsr_write(rt2x00dev, 41, 0x5b); | |
| 4120 | − rt2800_rfcsr_write(rt2x00dev, 42, 0x5b); | |
| 4121 | − rt2800_rfcsr_write(rt2x00dev, 43, 0xdb); | |
| 4122 | − rt2800_rfcsr_write(rt2x00dev, 44, 0xdb); | |
| 4123 | − rt2800_rfcsr_write(rt2x00dev, 45, 0xdb); | |
| 4124 | − rt2800_rfcsr_write(rt2x00dev, 46, 0xdd); | |
| 4125 | − rt2800_rfcsr_write(rt2x00dev, 47, 0x0d); | |
| 4126 | − rt2800_rfcsr_write(rt2x00dev, 48, 0x14); | |
| 4127 | − rt2800_rfcsr_write(rt2x00dev, 49, 0x00); | |
| 4128 | − rt2800_rfcsr_write(rt2x00dev, 50, 0x2d); | |
| 4129 | − rt2800_rfcsr_write(rt2x00dev, 51, 0x7f); | |
| 4130 | − rt2800_rfcsr_write(rt2x00dev, 52, 0x00); | |
| 4131 | − rt2800_rfcsr_write(rt2x00dev, 53, 0x52); | |
| 4132 | − rt2800_rfcsr_write(rt2x00dev, 54, 0x1b); | |
| 4133 | − rt2800_rfcsr_write(rt2x00dev, 55, 0x7f); | |
| 4134 | − rt2800_rfcsr_write(rt2x00dev, 56, 0x00); | |
| 4135 | − rt2800_rfcsr_write(rt2x00dev, 57, 0x52); | |
| 4136 | − rt2800_rfcsr_write(rt2x00dev, 58, 0x1b); | |
| 4137 | − rt2800_rfcsr_write(rt2x00dev, 59, 0x00); | |
| 4138 | − rt2800_rfcsr_write(rt2x00dev, 60, 0x00); | |
| 4139 | − rt2800_rfcsr_write(rt2x00dev, 61, 0x00); | |
| 4140 | − rt2800_rfcsr_write(rt2x00dev, 62, 0x00); | |
| 4141 | − rt2800_rfcsr_write(rt2x00dev, 63, 0x00); | |
| 4142 | − } else if (rt2x00_rt(rt2x00dev, RT5390)) { | |
| 4143 | − rt2800_rfcsr_write(rt2x00dev, 1, 0x0f); | |
| 4144 | − rt2800_rfcsr_write(rt2x00dev, 2, 0x80); | |
| 4145 | − rt2800_rfcsr_write(rt2x00dev, 3, 0x88); | |
| 4146 | − rt2800_rfcsr_write(rt2x00dev, 5, 0x10); | |
| 4147 | − if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4148 | − rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); | |
| 4149 | − else | |
| 4150 | − rt2800_rfcsr_write(rt2x00dev, 6, 0xa0); | |
| 4151 | − rt2800_rfcsr_write(rt2x00dev, 7, 0x00); | |
| 4152 | − rt2800_rfcsr_write(rt2x00dev, 10, 0x53); | |
| 4153 | − rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); | |
| 4154 | − rt2800_rfcsr_write(rt2x00dev, 12, 0xc6); | |
| 4155 | − rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); | |
| 4156 | − rt2800_rfcsr_write(rt2x00dev, 14, 0x00); | |
| 4157 | − rt2800_rfcsr_write(rt2x00dev, 15, 0x00); | |
| 4158 | − rt2800_rfcsr_write(rt2x00dev, 16, 0x00); | |
| 4159 | − rt2800_rfcsr_write(rt2x00dev, 18, 0x03); | |
| 4160 | − rt2800_rfcsr_write(rt2x00dev, 19, 0x00); | |
| 4161 | − | |
| 4162 | − rt2800_rfcsr_write(rt2x00dev, 20, 0x00); | |
| 4163 | − rt2800_rfcsr_write(rt2x00dev, 21, 0x00); | |
| 4164 | − rt2800_rfcsr_write(rt2x00dev, 22, 0x20); | |
| 4165 | − rt2800_rfcsr_write(rt2x00dev, 23, 0x00); | |
| 4166 | − rt2800_rfcsr_write(rt2x00dev, 24, 0x00); | |
| 4167 | − if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4168 | − rt2800_rfcsr_write(rt2x00dev, 25, 0x80); | |
| 4169 | − else | |
| 4170 | − rt2800_rfcsr_write(rt2x00dev, 25, 0xc0); | |
| 4171 | − rt2800_rfcsr_write(rt2x00dev, 26, 0x00); | |
| 4172 | − rt2800_rfcsr_write(rt2x00dev, 27, 0x09); | |
| 4173 | − rt2800_rfcsr_write(rt2x00dev, 28, 0x00); | |
| 4174 | − rt2800_rfcsr_write(rt2x00dev, 29, 0x10); | |
| 4175 | − | |
| 4176 | − rt2800_rfcsr_write(rt2x00dev, 30, 0x00); | |
| 4177 | − rt2800_rfcsr_write(rt2x00dev, 31, 0x80); | |
| 4178 | − rt2800_rfcsr_write(rt2x00dev, 32, 0x80); | |
| 4179 | − rt2800_rfcsr_write(rt2x00dev, 33, 0x00); | |
| 4180 | − rt2800_rfcsr_write(rt2x00dev, 34, 0x07); | |
| 4181 | − rt2800_rfcsr_write(rt2x00dev, 35, 0x12); | |
| 4182 | − rt2800_rfcsr_write(rt2x00dev, 36, 0x00); | |
| 4183 | − rt2800_rfcsr_write(rt2x00dev, 37, 0x08); | |
| 4184 | − rt2800_rfcsr_write(rt2x00dev, 38, 0x85); | |
| 4185 | − rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); | |
| 4186 | − | |
| 4187 | − if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4188 | − rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); | |
| 4189 | − else | |
| 4190 | − rt2800_rfcsr_write(rt2x00dev, 40, 0x4b); | |
| 4191 | − rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); | |
| 4192 | − rt2800_rfcsr_write(rt2x00dev, 42, 0xd2); | |
| 4193 | − rt2800_rfcsr_write(rt2x00dev, 43, 0x9a); | |
| 4194 | − rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); | |
| 4195 | − rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); | |
| 4196 | − if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4197 | − rt2800_rfcsr_write(rt2x00dev, 46, 0x73); | |
| 4198 | − else | |
| 4199 | − rt2800_rfcsr_write(rt2x00dev, 46, 0x7b); | |
| 4200 | − rt2800_rfcsr_write(rt2x00dev, 47, 0x00); | |
| 4201 | − rt2800_rfcsr_write(rt2x00dev, 48, 0x10); | |
| 4202 | − rt2800_rfcsr_write(rt2x00dev, 49, 0x94); | |
| 4203 | − | |
| 4204 | − rt2800_rfcsr_write(rt2x00dev, 52, 0x38); | |
| 4205 | − if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4206 | − rt2800_rfcsr_write(rt2x00dev, 53, 0x00); | |
| 4207 | − else | |
| 4208 | − rt2800_rfcsr_write(rt2x00dev, 53, 0x84); | |
| 4209 | − rt2800_rfcsr_write(rt2x00dev, 54, 0x78); | |
| 4210 | − rt2800_rfcsr_write(rt2x00dev, 55, 0x44); | |
| 4211 | − rt2800_rfcsr_write(rt2x00dev, 56, 0x22); | |
| 4212 | − rt2800_rfcsr_write(rt2x00dev, 57, 0x80); | |
| 4213 | − rt2800_rfcsr_write(rt2x00dev, 58, 0x7f); | |
| 4214 | − rt2800_rfcsr_write(rt2x00dev, 59, 0x63); | |
| 4215 | − | |
| 4216 | − rt2800_rfcsr_write(rt2x00dev, 60, 0x45); | |
| 4217 | − if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) | |
| 4218 | − rt2800_rfcsr_write(rt2x00dev, 61, 0xd1); | |
| 4219 | − else | |
| 4220 | − rt2800_rfcsr_write(rt2x00dev, 61, 0xdd); | |
| 4221 | − rt2800_rfcsr_write(rt2x00dev, 62, 0x00); | |
| 4222 | − rt2800_rfcsr_write(rt2x00dev, 63, 0x00); | |
| 4223 | − } else if (rt2x00_rt(rt2x00dev, RT5392)) { | |
| 4224 | − rt2800_rfcsr_write(rt2x00dev, 1, 0x17); | |
| 4225 | − rt2800_rfcsr_write(rt2x00dev, 2, 0x80); | |
| 4226 | − rt2800_rfcsr_write(rt2x00dev, 3, 0x88); | |
| 4227 | − rt2800_rfcsr_write(rt2x00dev, 5, 0x10); | |
| 4228 | − rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); | |
| 4229 | − rt2800_rfcsr_write(rt2x00dev, 7, 0x00); | |
| 4230 | − rt2800_rfcsr_write(rt2x00dev, 10, 0x53); | |
| 4231 | − rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); | |
| 4232 | − rt2800_rfcsr_write(rt2x00dev, 12, 0x46); | |
| 4233 | − rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); | |
| 4234 | − rt2800_rfcsr_write(rt2x00dev, 14, 0x00); | |
| 4235 | − rt2800_rfcsr_write(rt2x00dev, 15, 0x00); | |
| 4236 | − rt2800_rfcsr_write(rt2x00dev, 16, 0x00); | |
| 4237 | − rt2800_rfcsr_write(rt2x00dev, 18, 0x03); | |
| 4238 | − rt2800_rfcsr_write(rt2x00dev, 19, 0x4d); | |
| 4239 | − rt2800_rfcsr_write(rt2x00dev, 20, 0x00); | |
| 4240 | − rt2800_rfcsr_write(rt2x00dev, 21, 0x8d); | |
| 4241 | − rt2800_rfcsr_write(rt2x00dev, 22, 0x20); | |
| 4242 | − rt2800_rfcsr_write(rt2x00dev, 23, 0x0b); | |
| 4243 | − rt2800_rfcsr_write(rt2x00dev, 24, 0x44); | |
| 4244 | − rt2800_rfcsr_write(rt2x00dev, 25, 0x80); | |
| 4245 | − rt2800_rfcsr_write(rt2x00dev, 26, 0x82); | |
| 4246 | − rt2800_rfcsr_write(rt2x00dev, 27, 0x09); | |
| 4247 | − rt2800_rfcsr_write(rt2x00dev, 28, 0x00); | |
| 4248 | − rt2800_rfcsr_write(rt2x00dev, 29, 0x10); | |
| 4249 | − rt2800_rfcsr_write(rt2x00dev, 30, 0x10); | |
| 4250 | − rt2800_rfcsr_write(rt2x00dev, 31, 0x80); | |
| 4251 | − rt2800_rfcsr_write(rt2x00dev, 32, 0x20); | |
| 4252 | − rt2800_rfcsr_write(rt2x00dev, 33, 0xC0); | |
| 4253 | − rt2800_rfcsr_write(rt2x00dev, 34, 0x07); | |
| 4254 | − rt2800_rfcsr_write(rt2x00dev, 35, 0x12); | |
| 4255 | − rt2800_rfcsr_write(rt2x00dev, 36, 0x00); | |
| 4256 | − rt2800_rfcsr_write(rt2x00dev, 37, 0x08); | |
| 4257 | − rt2800_rfcsr_write(rt2x00dev, 38, 0x89); | |
| 4258 | − rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); | |
| 4259 | − rt2800_rfcsr_write(rt2x00dev, 40, 0x0f); | |
| 4260 | − rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); | |
| 4261 | − rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); | |
| 4262 | − rt2800_rfcsr_write(rt2x00dev, 43, 0x9b); | |
| 4263 | − rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); | |
| 4264 | − rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); | |
| 4265 | − rt2800_rfcsr_write(rt2x00dev, 46, 0x73); | |
| 4266 | − rt2800_rfcsr_write(rt2x00dev, 47, 0x0c); | |
| 4267 | − rt2800_rfcsr_write(rt2x00dev, 48, 0x10); | |
| 4268 | − rt2800_rfcsr_write(rt2x00dev, 49, 0x94); | |
| 4269 | − rt2800_rfcsr_write(rt2x00dev, 50, 0x94); | |
| 4270 | − rt2800_rfcsr_write(rt2x00dev, 51, 0x3a); | |
| 4271 | − rt2800_rfcsr_write(rt2x00dev, 52, 0x48); | |
| 4272 | − rt2800_rfcsr_write(rt2x00dev, 53, 0x44); | |
| 4273 | − rt2800_rfcsr_write(rt2x00dev, 54, 0x38); | |
| 4274 | − rt2800_rfcsr_write(rt2x00dev, 55, 0x43); | |
| 4275 | − rt2800_rfcsr_write(rt2x00dev, 56, 0xa1); | |
| 4276 | − rt2800_rfcsr_write(rt2x00dev, 57, 0x00); | |
| 4277 | − rt2800_rfcsr_write(rt2x00dev, 58, 0x39); | |
| 4278 | − rt2800_rfcsr_write(rt2x00dev, 59, 0x07); | |
| 4279 | − rt2800_rfcsr_write(rt2x00dev, 60, 0x45); | |
| 4280 | − rt2800_rfcsr_write(rt2x00dev, 61, 0x91); | |
| 4281 | − rt2800_rfcsr_write(rt2x00dev, 62, 0x39); | |
| 4282 | − rt2800_rfcsr_write(rt2x00dev, 63, 0x07); | |
| 4307 | + } | |
| 4308 | + | |
| 4309 | + switch (rt2x00dev->chip.rt) { | |
| 4310 | + case RT3070: | |
| 4311 | + case RT3071: | |
| 4312 | + case RT3090: | |
| 4313 | + rt2800_init_rfcsr_30xx(rt2x00dev); | |
| 4314 | + break; | |
| 4315 | + case RT3290: | |
| 4316 | + rt2800_init_rfcsr_3290(rt2x00dev); | |
| 4317 | + break; | |
| 4318 | + case RT3352: | |
| 4319 | + rt2800_init_rfcsr_3352(rt2x00dev); | |
| 4320 | + break; | |
| 4321 | + case RT3390: | |
| 4322 | + rt2800_init_rfcsr_3390(rt2x00dev); | |
| 4323 | + break; | |
| 4324 | + case RT3572: | |
| 4325 | + rt2800_init_rfcsr_3572(rt2x00dev); | |
| 4326 | + break; | |
| 4327 | + case RT5390: | |
| 4328 | + rt2800_init_rfcsr_5390(rt2x00dev); | |
| 4329 | + break; | |
| 4330 | + case RT5392: | |
| 4331 | + rt2800_init_rfcsr_5392(rt2x00dev); | |
| 4332 | + break; | |
| 4283 | 4333 | } |
| 4284 | 4334 | |
| 4285 | 4335 | if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) { |
| @@ -4620,12 +4670,14 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) · 334 unmodified lines | ||
| 4620 | 4670 | mutex_unlock(&rt2x00dev->csr_mutex); |
| 4621 | 4671 | } |
| 4622 | 4672 | |
| 4623 | −void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) | |
| 4673 | +int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) | |
| 4624 | 4674 | { |
| 4625 | 4675 | unsigned int i; |
| 4626 | 4676 | |
| 4627 | 4677 | for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8) |
| 4628 | 4678 | rt2800_efuse_read(rt2x00dev, i); |
| 4679 | + | |
| 4680 | + return 0; | |
| 4629 | 4681 | } |
| 4630 | 4682 | EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse); |
| 4631 | 4683 | |
| @@ -4635,11 +4687,14 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) · 3 unmodified lines | ||
| 4635 | 4687 | u16 word; |
| 4636 | 4688 | u8 *mac; |
| 4637 | 4689 | u8 default_lna_gain; |
| 4690 | + int retval; | |
| 4638 | 4691 | |
| 4639 | 4692 | /* |
| 4640 | 4693 | * Read the EEPROM. |
| 4641 | 4694 | */ |
| 4642 | − rt2800_read_eeprom(rt2x00dev); | |
| 4695 | + retval = rt2800_read_eeprom(rt2x00dev); | |
| 4696 | + if (retval) | |
| 4697 | + return retval; | |
| 4643 | 4698 | |
| 4644 | 4699 | /* |
| 4645 | 4700 | * Start validation of the data that has been read. |
| @@ -5090,8 +5145,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) · 444 unmodified lines | ||
| 5090 | 5145 | IEEE80211_HW_SUPPORTS_PS | |
| 5091 | 5146 | IEEE80211_HW_PS_NULLFUNC_STACK | |
| 5092 | 5147 | IEEE80211_HW_AMPDU_AGGREGATION | |
| 5093 | − IEEE80211_HW_REPORTS_TX_ACK_STATUS | | |
| 5094 | − IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL; | |
| 5148 | + IEEE80211_HW_REPORTS_TX_ACK_STATUS; | |
| 5095 | 5149 | |
| 5096 | 5150 | /* |
| 5097 | 5151 | * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices |
| @@ -43,7 +43,7 @@ struct rt2800_ops { · 42 unmodified lines | ||
| 43 | 43 | const unsigned int offset, |
| 44 | 44 | const struct rt2x00_field32 field, u32 *reg); |
| 45 | 45 | |
| 46 | − void (*read_eeprom)(struct rt2x00_dev *rt2x00dev); | |
| 46 | + int (*read_eeprom)(struct rt2x00_dev *rt2x00dev); | |
| 47 | 47 | bool (*hwcrypt_disabled)(struct rt2x00_dev *rt2x00dev); |
| 48 | 48 | |
| 49 | 49 | int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev, |
| @@ -117,11 +117,11 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, · 67 unmodified lines | ||
| 117 | 117 | return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg); |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | −static inline void rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev) | |
| 120 | +static inline int rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev) | |
| 121 | 121 | { |
| 122 | 122 | const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; |
| 123 | 123 | |
| 124 | − rt2800ops->read_eeprom(rt2x00dev); | |
| 124 | + return rt2800ops->read_eeprom(rt2x00dev); | |
| 125 | 125 | } |
| 126 | 126 | |
| 127 | 127 | static inline bool rt2800_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev) |
| @@ -207,7 +207,7 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); · 79 unmodified lines | ||
| 207 | 207 | void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); |
| 208 | 208 | |
| 209 | 209 | int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev); |
| 210 | −void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); | |
| 210 | +int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); | |
| 211 | 211 | |
| 212 | 212 | int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev); |
| 213 | 213 | |
| @@ -90,17 +90,22 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) · 89 unmodified lines | ||
| 90 | 90 | } |
| 91 | 91 | |
| 92 | 92 | #if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) |
| 93 | −static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) | |
| 93 | +static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) | |
| 94 | 94 | { |
| 95 | 95 | void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE); |
| 96 | 96 | |
| 97 | + if (!base_addr) | |
| 98 | + return -ENOMEM; | |
| 99 | + | |
| 97 | 100 | memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE); |
| 98 | 101 | |
| 99 | 102 | iounmap(base_addr); |
| 103 | + return 0; | |
| 100 | 104 | } |
| 101 | 105 | #else |
| 102 | −static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) | |
| 106 | +static inline int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) | |
| 103 | 107 | { |
| 108 | + return -ENOMEM; | |
| 104 | 109 | } |
| 105 | 110 | #endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ |
| 106 | 111 | |
| @@ -135,7 +140,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom) · 28 unmodified lines | ||
| 135 | 140 | rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg); |
| 136 | 141 | } |
| 137 | 142 | |
| 138 | −static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) | |
| 143 | +static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) | |
| 139 | 144 | { |
| 140 | 145 | struct eeprom_93cx6 eeprom; |
| 141 | 146 | u32 reg; |
| @@ -164,6 +169,8 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) · 22 unmodified lines | ||
| 164 | 169 | |
| 165 | 170 | eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, |
| 166 | 171 | EEPROM_SIZE / sizeof(u16)); |
| 172 | + | |
| 173 | + return 0; | |
| 167 | 174 | } |
| 168 | 175 | |
| 169 | 176 | static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) |
| @@ -171,13 +178,14 @@ static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) · 1 unmodified line | ||
| 171 | 178 | return rt2800_efuse_detect(rt2x00dev); |
| 172 | 179 | } |
| 173 | 180 | |
| 174 | −static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) | |
| 181 | +static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) | |
| 175 | 182 | { |
| 176 | − rt2800_read_eeprom_efuse(rt2x00dev); | |
| 183 | + return rt2800_read_eeprom_efuse(rt2x00dev); | |
| 177 | 184 | } |
| 178 | 185 | #else |
| 179 | −static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) | |
| 186 | +static inline int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) | |
| 180 | 187 | { |
| 188 | + return -EOPNOTSUPP; | |
| 181 | 189 | } |
| 182 | 190 | |
| 183 | 191 | static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) |
| @@ -185,8 +193,9 @@ static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) · 1 unmodified line | ||
| 185 | 193 | return 0; |
| 186 | 194 | } |
| 187 | 195 | |
| 188 | −static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) | |
| 196 | +static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) | |
| 189 | 197 | { |
| 198 | + return -EOPNOTSUPP; | |
| 190 | 199 | } |
| 191 | 200 | #endif /* CONFIG_PCI */ |
| 192 | 201 | |
| @@ -970,14 +979,18 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) · 777 unmodified lines | ||
| 970 | 979 | /* |
| 971 | 980 | * Device probe functions. |
| 972 | 981 | */ |
| 973 | −static void rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev) | |
| 982 | +static int rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev) | |
| 974 | 983 | { |
| 984 | + int retval; | |
| 985 | + | |
| 975 | 986 | if (rt2x00_is_soc(rt2x00dev)) |
| 976 | − rt2800pci_read_eeprom_soc(rt2x00dev); | |
| 987 | + retval = rt2800pci_read_eeprom_soc(rt2x00dev); | |
| 977 | 988 | else if (rt2800pci_efuse_detect(rt2x00dev)) |
| 978 | − rt2800pci_read_eeprom_efuse(rt2x00dev); | |
| 989 | + retval = rt2800pci_read_eeprom_efuse(rt2x00dev); | |
| 979 | 990 | else |
| 980 | − rt2800pci_read_eeprom_pci(rt2x00dev); | |
| 991 | + retval = rt2800pci_read_eeprom_pci(rt2x00dev); | |
| 992 | + | |
| 993 | + return retval; | |
| 981 | 994 | } |
| 982 | 995 | |
| 983 | 996 | static const struct ieee80211_ops rt2800pci_mac80211_ops = { |
| @@ -735,13 +735,17 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, · 734 unmodified lines | ||
| 735 | 735 | /* |
| 736 | 736 | * Device probe functions. |
| 737 | 737 | */ |
| 738 | −static void rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev) | |
| 738 | +static int rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev) | |
| 739 | 739 | { |
| 740 | + int retval; | |
| 741 | + | |
| 740 | 742 | if (rt2800_efuse_detect(rt2x00dev)) |
| 741 | − rt2800_read_eeprom_efuse(rt2x00dev); | |
| 743 | + retval = rt2800_read_eeprom_efuse(rt2x00dev); | |
| 742 | 744 | else |
| 743 | − rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, | |
| 744 | − EEPROM_SIZE); | |
| 745 | + retval = rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, | |
| 746 | + EEPROM_SIZE); | |
| 747 | + | |
| 748 | + return retval; | |
| 745 | 749 | } |
| 746 | 750 | |
| 747 | 751 | static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) |
| @@ -1016,6 +1016,26 @@ struct rt2x00_dev { · 1015 unmodified lines | ||
| 1016 | 1016 | * Protect the interrupt mask register. |
| 1017 | 1017 | */ |
| 1018 | 1018 | spinlock_t irqmask_lock; |
| 1019 | + | |
| 1020 | + /* | |
| 1021 | + * List of BlockAckReq TX entries that need driver BlockAck processing. | |
| 1022 | + */ | |
| 1023 | + struct list_head bar_list; | |
| 1024 | + spinlock_t bar_list_lock; | |
| 1025 | +}; | |
| 1026 | + | |
| 1027 | +struct rt2x00_bar_list_entry { | |
| 1028 | + struct list_head list; | |
| 1029 | + struct rcu_head head; | |
| 1030 | + | |
| 1031 | + struct queue_entry *entry; | |
| 1032 | + int block_acked; | |
| 1033 | + | |
| 1034 | + /* Relevant parts of the IEEE80211 BAR header */ | |
| 1035 | + __u8 ra[6]; | |
| 1036 | + __u8 ta[6]; | |
| 1037 | + __le16 control; | |
| 1038 | + __le16 start_seq_num; | |
| 1019 | 1039 | }; |
| 1020 | 1040 | |
| 1021 | 1041 | /* |
| @@ -271,6 +271,50 @@ void rt2x00lib_dmadone(struct queue_entry *entry) · 270 unmodified lines | ||
| 271 | 271 | } |
| 272 | 272 | EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); |
| 273 | 273 | |
| 274 | +static inline int rt2x00lib_txdone_bar_status(struct queue_entry *entry) | |
| 275 | +{ | |
| 276 | + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | |
| 277 | + struct ieee80211_bar *bar = (void *) entry->skb->data; | |
| 278 | + struct rt2x00_bar_list_entry *bar_entry; | |
| 279 | + int ret; | |
| 280 | + | |
| 281 | + if (likely(!ieee80211_is_back_req(bar->frame_control))) | |
| 282 | + return 0; | |
| 283 | + | |
| 284 | + /* | |
| 285 | + * Unlike all other frames, the status report for BARs does | |
| 286 | + * not directly come from the hardware as it is incapable of | |
| 287 | + * matching a BA to a previously send BAR. The hardware will | |
| 288 | + * report all BARs as if they weren't acked at all. | |
| 289 | + * | |
| 290 | + * Instead the RX-path will scan for incoming BAs and set the | |
| 291 | + * block_acked flag if it sees one that was likely caused by | |
| 292 | + * a BAR from us. | |
| 293 | + * | |
| 294 | + * Remove remaining BARs here and return their status for | |
| 295 | + * TX done processing. | |
| 296 | + */ | |
| 297 | + ret = 0; | |
| 298 | + rcu_read_lock(); | |
| 299 | + list_for_each_entry_rcu(bar_entry, &rt2x00dev->bar_list, list) { | |
| 300 | + if (bar_entry->entry != entry) | |
| 301 | + continue; | |
| 302 | + | |
| 303 | + spin_lock_bh(&rt2x00dev->bar_list_lock); | |
| 304 | + /* Return whether this BAR was blockacked or not */ | |
| 305 | + ret = bar_entry->block_acked; | |
| 306 | + /* Remove the BAR from our checklist */ | |
| 307 | + list_del_rcu(&bar_entry->list); | |
| 308 | + spin_unlock_bh(&rt2x00dev->bar_list_lock); | |
| 309 | + kfree_rcu(bar_entry, head); | |
| 310 | + | |
| 311 | + break; | |
| 312 | + } | |
| 313 | + rcu_read_unlock(); | |
| 314 | + | |
| 315 | + return ret; | |
| 316 | +} | |
| 317 | + | |
| 274 | 318 | void rt2x00lib_txdone(struct queue_entry *entry, |
| 275 | 319 | struct txdone_entry_desc *txdesc) |
| 276 | 320 | { |
| @@ -324,9 +368,12 @@ void rt2x00lib_txdone(struct queue_entry *entry, · 47 unmodified lines | ||
| 324 | 368 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); |
| 325 | 369 | |
| 326 | 370 | /* |
| 327 | − * Determine if the frame has been successfully transmitted. | |
| 371 | + * Determine if the frame has been successfully transmitted and | |
| 372 | + * remove BARs from our check list while checking for their | |
| 373 | + * TX status. | |
| 328 | 374 | */ |
| 329 | 375 | success = |
| 376 | + rt2x00lib_txdone_bar_status(entry) || | |
| 330 | 377 | test_bit(TXDONE_SUCCESS, &txdesc->flags) || |
| 331 | 378 | test_bit(TXDONE_UNKNOWN, &txdesc->flags); |
| 332 | 379 | |
| @@ -491,6 +538,50 @@ static void rt2x00lib_sleep(struct work_struct *work) · 158 unmodified lines | ||
| 491 | 538 | IEEE80211_CONF_CHANGE_PS); |
| 492 | 539 | } |
| 493 | 540 | |
| 541 | +static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev, | |
| 542 | + struct sk_buff *skb, | |
| 543 | + struct rxdone_entry_desc *rxdesc) | |
| 544 | +{ | |
| 545 | + struct rt2x00_bar_list_entry *entry; | |
| 546 | + struct ieee80211_bar *ba = (void *)skb->data; | |
| 547 | + | |
| 548 | + if (likely(!ieee80211_is_back(ba->frame_control))) | |
| 549 | + return; | |
| 550 | + | |
| 551 | + if (rxdesc->size < sizeof(*ba) + FCS_LEN) | |
| 552 | + return; | |
| 553 | + | |
| 554 | + rcu_read_lock(); | |
| 555 | + list_for_each_entry_rcu(entry, &rt2x00dev->bar_list, list) { | |
| 556 | + | |
| 557 | + if (ba->start_seq_num != entry->start_seq_num) | |
| 558 | + continue; | |
| 559 | + | |
| 560 | +#define TID_CHECK(a, b) ( \ | |
| 561 | + ((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) == \ | |
| 562 | + ((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK))) \ | |
| 563 | + | |
| 564 | + if (!TID_CHECK(ba->control, entry->control)) | |
| 565 | + continue; | |
| 566 | + | |
| 567 | +#undef TID_CHECK | |
| 568 | + | |
| 569 | + if (compare_ether_addr(ba->ra, entry->ta)) | |
| 570 | + continue; | |
| 571 | + | |
| 572 | + if (compare_ether_addr(ba->ta, entry->ra)) | |
| 573 | + continue; | |
| 574 | + | |
| 575 | + /* Mark BAR since we received the according BA */ | |
| 576 | + spin_lock_bh(&rt2x00dev->bar_list_lock); | |
| 577 | + entry->block_acked = 1; | |
| 578 | + spin_unlock_bh(&rt2x00dev->bar_list_lock); | |
| 579 | + break; | |
| 580 | + } | |
| 581 | + rcu_read_unlock(); | |
| 582 | + | |
| 583 | +} | |
| 584 | + | |
| 494 | 585 | static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, |
| 495 | 586 | struct sk_buff *skb, |
| 496 | 587 | struct rxdone_entry_desc *rxdesc) |
| @@ -673,6 +764,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp) · 176 unmodified lines | ||
| 673 | 764 | */ |
| 674 | 765 | rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc); |
| 675 | 766 | |
| 767 | + /* | |
| 768 | + * Check for incoming BlockAcks to match to the BlockAckReqs | |
| 769 | + * we've send out. | |
| 770 | + */ | |
| 771 | + rt2x00lib_rxdone_check_ba(rt2x00dev, entry->skb, &rxdesc); | |
| 772 | + | |
| 676 | 773 | /* |
| 677 | 774 | * Update extra components |
| 678 | 775 | */ |
| @@ -1183,6 +1280,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) · 504 unmodified lines | ||
| 1183 | 1280 | |
| 1184 | 1281 | spin_lock_init(&rt2x00dev->irqmask_lock); |
| 1185 | 1282 | mutex_init(&rt2x00dev->csr_mutex); |
| 1283 | + INIT_LIST_HEAD(&rt2x00dev->bar_list); | |
| 1284 | + spin_lock_init(&rt2x00dev->bar_list_lock); | |
| 1186 | 1285 | |
| 1187 | 1286 | set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); |
| 1188 | 1287 | |
| @@ -582,6 +582,48 @@ static void rt2x00queue_kick_tx_queue(struct data_queue *queue, · 581 unmodified lines | ||
| 582 | 582 | queue->rt2x00dev->ops->lib->kick_queue(queue); |
| 583 | 583 | } |
| 584 | 584 | |
| 585 | +static void rt2x00queue_bar_check(struct queue_entry *entry) | |
| 586 | +{ | |
| 587 | + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | |
| 588 | + struct ieee80211_bar *bar = (void *) (entry->skb->data + | |
| 589 | + rt2x00dev->ops->extra_tx_headroom); | |
| 590 | + struct rt2x00_bar_list_entry *bar_entry; | |
| 591 | + | |
| 592 | + if (likely(!ieee80211_is_back_req(bar->frame_control))) | |
| 593 | + return; | |
| 594 | + | |
| 595 | + bar_entry = kmalloc(sizeof(*bar_entry), GFP_ATOMIC); | |
| 596 | + | |
| 597 | + /* | |
| 598 | + * If the alloc fails we still send the BAR out but just don't track | |
| 599 | + * it in our bar list. And as a result we will report it to mac80211 | |
| 600 | + * back as failed. | |
| 601 | + */ | |
| 602 | + if (!bar_entry) | |
| 603 | + return; | |
| 604 | + | |
| 605 | + bar_entry->entry = entry; | |
| 606 | + bar_entry->block_acked = 0; | |
| 607 | + | |
| 608 | + /* | |
| 609 | + * Copy the relevant parts of the 802.11 BAR into out check list | |
| 610 | + * such that we can use RCU for less-overhead in the RX path since | |
| 611 | + * sending BARs and processing the according BlockAck should be | |
| 612 | + * the exception. | |
| 613 | + */ | |
| 614 | + memcpy(bar_entry->ra, bar->ra, sizeof(bar->ra)); | |
| 615 | + memcpy(bar_entry->ta, bar->ta, sizeof(bar->ta)); | |
| 616 | + bar_entry->control = bar->control; | |
| 617 | + bar_entry->start_seq_num = bar->start_seq_num; | |
| 618 | + | |
| 619 | + /* | |
| 620 | + * Insert BAR into our BAR check list. | |
| 621 | + */ | |
| 622 | + spin_lock_bh(&rt2x00dev->bar_list_lock); | |
| 623 | + list_add_tail_rcu(&bar_entry->list, &rt2x00dev->bar_list); | |
| 624 | + spin_unlock_bh(&rt2x00dev->bar_list_lock); | |
| 625 | +} | |
| 626 | + | |
| 585 | 627 | int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, |
| 586 | 628 | bool local) |
| 587 | 629 | { |
| @@ -680,6 +722,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, · 92 unmodified lines | ||
| 680 | 722 | goto out; |
| 681 | 723 | } |
| 682 | 724 | |
| 725 | + /* | |
| 726 | + * Put BlockAckReqs into our check list for driver BA processing. | |
| 727 | + */ | |
| 728 | + rt2x00queue_bar_check(entry); | |
| 729 | + | |
| 683 | 730 | set_bit(ENTRY_DATA_PENDING, &entry->flags); |
| 684 | 731 | |
| 685 | 732 | rt2x00queue_index_inc(entry, Q_INDEX); |
| @@ -57,12 +57,12 @@ config RTL8192CU · 56 unmodified lines | ||
| 57 | 57 | |
| 58 | 58 | config RTLWIFI |
| 59 | 59 | tristate |
| 60 | − depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE | |
| 60 | + depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE | |
| 61 | 61 | default m |
| 62 | 62 | |
| 63 | 63 | config RTLWIFI_DEBUG |
| 64 | 64 | bool "Additional debugging output" |
| 65 | − depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE | |
| 65 | + depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE | |
| 66 | 66 | default y |
| 67 | 67 | |
| 68 | 68 | config RTL8192C_COMMON |
| @@ -743,6 +743,8 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) · 742 unmodified lines | ||
| 743 | 743 | |
| 744 | 744 | done: |
| 745 | 745 | bufferaddress = (*((dma_addr_t *)skb->cb)); |
| 746 | + if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress)) | |
| 747 | + return; | |
| 746 | 748 | tmp_one = 1; |
| 747 | 749 | rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, |
| 748 | 750 | HW_DESC_RXBUFF_ADDR, |
| @@ -1115,6 +1117,10 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) · 366 unmodified lines | ||
| 1115 | 1117 | PCI_DMA_FROMDEVICE); |
| 1116 | 1118 | |
| 1117 | 1119 | bufferaddress = (*((dma_addr_t *)skb->cb)); |
| 1120 | + if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress)) { | |
| 1121 | + dev_kfree_skb_any(skb); | |
| 1122 | + return 1; | |
| 1123 | + } | |
| 1118 | 1124 | rtlpriv->cfg->ops->set_desc((u8 *)entry, false, |
| 1119 | 1125 | HW_DESC_RXBUFF_ADDR, |
| 1120 | 1126 | (u8 *)&bufferaddress); |
| @@ -692,7 +692,7 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw) · 691 unmodified lines | ||
| 692 | 692 | if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { |
| 693 | 693 | rtl92c_phy_sw_chnl_callback(hw); |
| 694 | 694 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
| 695 | − "sw_chnl_inprogress false schdule workitem\n"); | |
| 695 | + "sw_chnl_inprogress false schedule workitem\n"); | |
| 696 | 696 | rtlphy->sw_chnl_inprogress = false; |
| 697 | 697 | } else { |
| 698 | 698 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
| @@ -611,8 +611,14 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, · 610 unmodified lines | ||
| 611 | 611 | dma_addr_t mapping = pci_map_single(rtlpci->pdev, |
| 612 | 612 | skb->data, skb->len, |
| 613 | 613 | PCI_DMA_TODEVICE); |
| 614 | + | |
| 614 | 615 | u8 bw_40 = 0; |
| 615 | 616 | |
| 617 | + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { | |
| 618 | + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, | |
| 619 | + "DMA mapping error"); | |
| 620 | + return; | |
| 621 | + } | |
| 616 | 622 | rcu_read_lock(); |
| 617 | 623 | sta = get_sta(hw, mac->vif, mac->bssid); |
| 618 | 624 | if (mac->opmode == NL80211_IFTYPE_STATION) { |
| @@ -774,6 +780,11 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, · 155 unmodified lines | ||
| 774 | 780 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); |
| 775 | 781 | __le16 fc = hdr->frame_control; |
| 776 | 782 | |
| 783 | + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { | |
| 784 | + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, | |
| 785 | + "DMA mapping error"); | |
| 786 | + return; | |
| 787 | + } | |
| 777 | 788 | CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); |
| 778 | 789 | |
| 779 | 790 | if (firstseg) |
| @@ -452,7 +452,7 @@ static void _rtl92de_translate_rx_signal_stuff(struct ieee80211_hw *hw, · 451 unmodified lines | ||
| 452 | 452 | u8 *praddr; |
| 453 | 453 | u16 type, cfc; |
| 454 | 454 | __le16 fc; |
| 455 | − bool packet_matchbssid, packet_toself, packet_beacon; | |
| 455 | + bool packet_matchbssid, packet_toself, packet_beacon = false; | |
| 456 | 456 | |
| 457 | 457 | tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; |
| 458 | 458 | hdr = (struct ieee80211_hdr *)tmp_buf; |
| @@ -587,6 +587,11 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, · 128 unmodified lines | ||
| 587 | 587 | buf_len = skb->len; |
| 588 | 588 | mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, |
| 589 | 589 | PCI_DMA_TODEVICE); |
| 590 | + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { | |
| 591 | + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, | |
| 592 | + "DMA mapping error"); | |
| 593 | + return; | |
| 594 | + } | |
| 590 | 595 | CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92d)); |
| 591 | 596 | if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { |
| 592 | 597 | firstseg = true; |
| @@ -740,6 +745,11 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, · 147 unmodified lines | ||
| 740 | 745 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); |
| 741 | 746 | __le16 fc = hdr->frame_control; |
| 742 | 747 | |
| 748 | + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { | |
| 749 | + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, | |
| 750 | + "DMA mapping error"); | |
| 751 | + return; | |
| 752 | + } | |
| 743 | 753 | CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); |
| 744 | 754 | if (firstseg) |
| 745 | 755 | SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); |
| @@ -480,7 +480,7 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, · 479 unmodified lines | ||
| 480 | 480 | u8 *praddr; |
| 481 | 481 | __le16 fc; |
| 482 | 482 | u16 type, cfc; |
| 483 | − bool packet_matchbssid, packet_toself, packet_beacon; | |
| 483 | + bool packet_matchbssid, packet_toself, packet_beacon = false; | |
| 484 | 484 | |
| 485 | 485 | tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; |
| 486 | 486 | |
| @@ -611,6 +611,11 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, · 124 unmodified lines | ||
| 611 | 611 | PCI_DMA_TODEVICE); |
| 612 | 612 | u8 bw_40 = 0; |
| 613 | 613 | |
| 614 | + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { | |
| 615 | + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, | |
| 616 | + "DMA mapping error"); | |
| 617 | + return; | |
| 618 | + } | |
| 614 | 619 | if (mac->opmode == NL80211_IFTYPE_STATION) { |
| 615 | 620 | bw_40 = mac->bw_40; |
| 616 | 621 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
| @@ -763,6 +768,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, · 146 unmodified lines | ||
| 763 | 768 | void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, |
| 764 | 769 | bool firstseg, bool lastseg, struct sk_buff *skb) |
| 765 | 770 | { |
| 771 | + struct rtl_priv *rtlpriv = rtl_priv(hw); | |
| 766 | 772 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); |
| 767 | 773 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); |
| 768 | 774 | struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb); |
| @@ -770,7 +776,12 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, · 1 unmodified line | ||
| 770 | 776 | dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, |
| 771 | 777 | PCI_DMA_TODEVICE); |
| 772 | 778 | |
| 773 | − /* Clear all status */ | |
| 779 | + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { | |
| 780 | + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, | |
| 781 | + "DMA mapping error"); | |
| 782 | + return; | |
| 783 | + } | |
| 784 | + /* Clear all status */ | |
| 774 | 785 | CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_CMDDESC_SIZE_RTL8192S); |
| 775 | 786 | |
| 776 | 787 | /* This bit indicate this packet is used for FW download. */ |
| @@ -1106,7 +1106,7 @@ u8 rtl8723ae_phy_sw_chnl(struct ieee80211_hw *hw) · 1105 unmodified lines | ||
| 1106 | 1106 | if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { |
| 1107 | 1107 | rtl8723ae_phy_sw_chnl_callback(hw); |
| 1108 | 1108 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
| 1109 | − "sw_chnl_inprogress false schdule workitem\n"); | |
| 1109 | + "sw_chnl_inprogress false schedule workitem\n"); | |
| 1110 | 1110 | rtlphy->sw_chnl_inprogress = false; |
| 1111 | 1111 | } else { |
| 1112 | 1112 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
| @@ -247,7 +247,7 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw, · 246 unmodified lines | ||
| 247 | 247 | u8 *psaddr; |
| 248 | 248 | __le16 fc; |
| 249 | 249 | u16 type; |
| 250 | − bool packet_matchbssid, packet_toself, packet_beacon; | |
| 250 | + bool packet_matchbssid, packet_toself, packet_beacon = false; | |
| 251 | 251 | |
| 252 | 252 | tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift; |
| 253 | 253 | |
| @@ -387,6 +387,11 @@ void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, · 133 unmodified lines | ||
| 387 | 387 | PCI_DMA_TODEVICE); |
| 388 | 388 | u8 bw_40 = 0; |
| 389 | 389 | |
| 390 | + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { | |
| 391 | + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, | |
| 392 | + "DMA mapping error"); | |
| 393 | + return; | |
| 394 | + } | |
| 390 | 395 | if (mac->opmode == NL80211_IFTYPE_STATION) { |
| 391 | 396 | bw_40 = mac->bw_40; |
| 392 | 397 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
| @@ -542,6 +547,11 @@ void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, · 149 unmodified lines | ||
| 542 | 547 | PCI_DMA_TODEVICE); |
| 543 | 548 | __le16 fc = hdr->frame_control; |
| 544 | 549 | |
| 550 | + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { | |
| 551 | + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, | |
| 552 | + "DMA mapping error"); | |
| 553 | + return; | |
| 554 | + } | |
| 545 | 555 | CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); |
| 546 | 556 | |
| 547 | 557 | if (firstseg) |
| @@ -210,17 +210,16 @@ static void _usb_writeN_sync(struct rtl_priv *rtlpriv, u32 addr, void *data, · 209 unmodified lines | ||
| 210 | 210 | u16 index = REALTEK_USB_VENQT_CMD_IDX; |
| 211 | 211 | int pipe = usb_sndctrlpipe(udev, 0); /* write_out */ |
| 212 | 212 | u8 *buffer; |
| 213 | − dma_addr_t dma_addr; | |
| 214 | 213 | |
| 215 | − wvalue = (u16)(addr&0x0000ffff); | |
| 216 | − buffer = usb_alloc_coherent(udev, (size_t)len, GFP_ATOMIC, &dma_addr); | |
| 214 | + wvalue = (u16)(addr & 0x0000ffff); | |
| 215 | + buffer = kmalloc(len, GFP_ATOMIC); | |
| 217 | 216 | if (!buffer) |
| 218 | 217 | return; |
| 219 | 218 | memcpy(buffer, data, len); |
| 220 | 219 | usb_control_msg(udev, pipe, request, reqtype, wvalue, |
| 221 | 220 | index, buffer, len, 50); |
| 222 | 221 | |
| 223 | − usb_free_coherent(udev, (size_t)len, buffer, dma_addr); | |
| 222 | + kfree(buffer); | |
| 224 | 223 | } |
| 225 | 224 | |
| 226 | 225 | static void _rtl_usb_io_handler_init(struct device *dev, |
| @@ -640,6 +639,7 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw) · 413 unmodified lines | ||
| 640 | 639 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, |
| 641 | 640 | "Failed to prep_rx_urb!!\n"); |
| 642 | 641 | err = PTR_ERR(skb); |
| 642 | + usb_free_urb(urb); | |
| 643 | 643 | goto err_out; |
| 644 | 644 | } |
| 645 | 645 | |
| @@ -5,19 +5,6 @@ · 4 unmodified lines | ||
| 5 | 5 | menu "Near Field Communication (NFC) devices" |
| 6 | 6 | depends on NFC |
| 7 | 7 | |
| 8 | −config PN544_HCI_NFC | |
| 9 | − tristate "HCI PN544 NFC driver" | |
| 10 | − depends on I2C && NFC_HCI && NFC_SHDLC | |
| 11 | − select CRC_CCITT | |
| 12 | − default n | |
| 13 | − ---help--- | |
| 14 | − NXP PN544 i2c driver. | |
| 15 | − This is a driver based on the SHDLC and HCI NFC kernel layers and | |
| 16 | − will thus not work with NXP libnfc library. | |
| 17 | − | |
| 18 | − To compile this driver as a module, choose m here. The module will | |
| 19 | − be called pn544_hci. | |
| 20 | − | |
| 21 | 8 | config NFC_PN533 |
| 22 | 9 | tristate "NXP PN533 USB driver" |
| 23 | 10 | depends on USB |
| @@ -39,4 +26,6 @@ config NFC_WILINK · 15 unmodified lines | ||
| 39 | 26 | Say Y here to compile support for Texas Instrument's NFC WiLink driver |
| 40 | 27 | into the kernel or say M to compile it as module. |
| 41 | 28 | |
| 29 | +source "drivers/nfc/pn544/Kconfig" | |
| 30 | + | |
| 42 | 31 | endmenu |
| @@ -2,7 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | # Makefile for nfc devices |
| 3 | 3 | # |
| 4 | 4 | |
| 5 | −obj-$(CONFIG_PN544_HCI_NFC) += pn544/ | |
| 5 | +obj-$(CONFIG_NFC_PN544) += pn544/ | |
| 6 | 6 | obj-$(CONFIG_NFC_PN533) += pn533.o |
| 7 | 7 | obj-$(CONFIG_NFC_WILINK) += nfcwilink.o |
| 8 | 8 | |
| @@ -526,7 +526,7 @@ static int nfcwilink_probe(struct platform_device *pdev) · 525 unmodified lines | ||
| 526 | 526 | |
| 527 | 527 | nfc_dev_dbg(&pdev->dev, "probe entry"); |
| 528 | 528 | |
| 529 | − drv = kzalloc(sizeof(struct nfcwilink), GFP_KERNEL); | |
| 529 | + drv = devm_kzalloc(&pdev->dev, sizeof(struct nfcwilink), GFP_KERNEL); | |
| 530 | 530 | if (!drv) { |
| 531 | 531 | rc = -ENOMEM; |
| 532 | 532 | goto exit; |
| @@ -542,12 +542,13 @@ static int nfcwilink_probe(struct platform_device *pdev) · 9 unmodified lines | ||
| 542 | 542 | |
| 543 | 543 | drv->ndev = nci_allocate_device(&nfcwilink_ops, |
| 544 | 544 | protocols, |
| 545 | + NFC_SE_NONE, | |
| 545 | 546 | NFCWILINK_HDR_LEN, |
| 546 | 547 | 0); |
| 547 | 548 | if (!drv->ndev) { |
| 548 | 549 | nfc_dev_err(&pdev->dev, "nci_allocate_device failed"); |
| 549 | 550 | rc = -ENOMEM; |
| 550 | − goto free_exit; | |
| 551 | + goto exit; | |
| 551 | 552 | } |
| 552 | 553 | |
| 553 | 554 | nci_set_parent_dev(drv->ndev, &pdev->dev); |
| @@ -566,9 +567,6 @@ static int nfcwilink_probe(struct platform_device *pdev) · 12 unmodified lines | ||
| 566 | 567 | free_dev_exit: |
| 567 | 568 | nci_free_device(drv->ndev); |
| 568 | 569 | |
| 569 | −free_exit: | |
| 570 | − kfree(drv); | |
| 571 | − | |
| 572 | 570 | exit: |
| 573 | 571 | return rc; |
| 574 | 572 | } |
| @@ -588,8 +586,6 @@ static int nfcwilink_remove(struct platform_device *pdev) · 13 unmodified lines | ||
| 588 | 586 | nci_unregister_device(ndev); |
| 589 | 587 | nci_free_device(ndev); |
| 590 | 588 | |
| 591 | − kfree(drv); | |
| 592 | − | |
| 593 | 589 | dev_set_drvdata(&pdev->dev, NULL); |
| 594 | 590 | |
| 595 | 591 | return 0; |
| @@ -41,11 +41,6 @@ · 40 unmodified lines | ||
| 41 | 41 | #define SONY_VENDOR_ID 0x054c |
| 42 | 42 | #define PASORI_PRODUCT_ID 0x02e1 |
| 43 | 43 | |
| 44 | −#define PN533_QUIRKS_TYPE_A BIT(0) | |
| 45 | −#define PN533_QUIRKS_TYPE_F BIT(1) | |
| 46 | −#define PN533_QUIRKS_DEP BIT(2) | |
| 47 | −#define PN533_QUIRKS_RAW_EXCHANGE BIT(3) | |
| 48 | − | |
| 49 | 44 | #define PN533_DEVICE_STD 0x1 |
| 50 | 45 | #define PN533_DEVICE_PASORI 0x2 |
| 51 | 46 | |
| @@ -84,14 +79,18 @@ MODULE_DEVICE_TABLE(usb, pn533_table); · 32 unmodified lines | ||
| 84 | 79 | #define PN533_LISTEN_TIME 2 |
| 85 | 80 | |
| 86 | 81 | /* frame definitions */ |
| 87 | −#define PN533_NORMAL_FRAME_MAX_LEN 262 /* 6 (PREAMBLE, SOF, LEN, LCS, TFI) | |
| 88 | − 254 (DATA) | |
| 89 | − 2 (DCS, postamble) */ | |
| 90 | − | |
| 91 | −#define PN533_FRAME_TAIL_SIZE 2 | |
| 92 | −#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \ | |
| 93 | − PN533_FRAME_TAIL_SIZE) | |
| 94 | −#define PN533_FRAME_ACK_SIZE (sizeof(struct pn533_frame) + 1) | |
| 82 | +#define PN533_FRAME_HEADER_LEN (sizeof(struct pn533_frame) \ | |
| 83 | + + 2) /* data[0] TFI, data[1] CC */ | |
| 84 | +#define PN533_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/ | |
| 85 | + | |
| 86 | +/* | |
| 87 | + * Max extended frame payload len, excluding TFI and CC | |
| 88 | + * which are already in PN533_FRAME_HEADER_LEN. | |
| 89 | + */ | |
| 90 | +#define PN533_FRAME_MAX_PAYLOAD_LEN 263 | |
| 91 | + | |
| 92 | +#define PN533_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2), | |
| 93 | + Postamble (1) */ | |
| 95 | 94 | #define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen]) |
| 96 | 95 | #define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1]) |
| 97 | 96 | |
| @@ -105,8 +104,6 @@ MODULE_DEVICE_TABLE(usb, pn533_table); · 7 unmodified lines | ||
| 105 | 104 | |
| 106 | 105 | /* PN533 Commands */ |
| 107 | 106 | #define PN533_FRAME_CMD(f) (f->data[1]) |
| 108 | −#define PN533_FRAME_CMD_PARAMS_PTR(f) (&f->data[2]) | |
| 109 | −#define PN533_FRAME_CMD_PARAMS_LEN(f) (f->datalen - 2) | |
| 110 | 107 | |
| 111 | 108 | #define PN533_CMD_GET_FIRMWARE_VERSION 0x02 |
| 112 | 109 | #define PN533_CMD_RF_CONFIGURATION 0x32 |
| @@ -120,6 +117,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table); · 7 unmodified lines | ||
| 120 | 117 | #define PN533_CMD_TG_INIT_AS_TARGET 0x8c |
| 121 | 118 | #define PN533_CMD_TG_GET_DATA 0x86 |
| 122 | 119 | #define PN533_CMD_TG_SET_DATA 0x8e |
| 120 | +#define PN533_CMD_UNDEF 0xff | |
| 123 | 121 | |
| 124 | 122 | #define PN533_CMD_RESPONSE(cmd) (cmd + 1) |
| 125 | 123 | |
| @@ -128,13 +126,12 @@ MODULE_DEVICE_TABLE(usb, pn533_table); · 2 unmodified lines | ||
| 128 | 126 | #define PN533_CMD_MI_MASK 0x40 |
| 129 | 127 | #define PN533_CMD_RET_SUCCESS 0x00 |
| 130 | 128 | |
| 131 | −/* PN533 status codes */ | |
| 132 | −#define PN533_STATUS_TARGET_RELEASED 0x29 | |
| 133 | − | |
| 134 | 129 | struct pn533; |
| 135 | 130 | |
| 136 | −typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, | |
| 137 | − u8 *params, int params_len); | |
| 131 | +typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, int status); | |
| 132 | + | |
| 133 | +typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg, | |
| 134 | + struct sk_buff *resp); | |
| 138 | 135 | |
| 139 | 136 | /* structs for pn533 commands */ |
| 140 | 137 | |
| @@ -282,11 +279,6 @@ const struct pn533_poll_modulations poll_mod[] = { · 141 unmodified lines | ||
| 282 | 279 | |
| 283 | 280 | /* PN533_CMD_IN_ATR */ |
| 284 | 281 | |
| 285 | −struct pn533_cmd_activate_param { | |
| 286 | − u8 tg; | |
| 287 | − u8 next; | |
| 288 | −} __packed; | |
| 289 | − | |
| 290 | 282 | struct pn533_cmd_activate_response { |
| 291 | 283 | u8 status; |
| 292 | 284 | u8 nfcid3t[10]; |
| @@ -299,14 +291,6 @@ struct pn533_cmd_activate_response { · 6 unmodified lines | ||
| 299 | 291 | u8 gt[]; |
| 300 | 292 | } __packed; |
| 301 | 293 | |
| 302 | −/* PN533_CMD_IN_JUMP_FOR_DEP */ | |
| 303 | −struct pn533_cmd_jump_dep { | |
| 304 | − u8 active; | |
| 305 | − u8 baud; | |
| 306 | − u8 next; | |
| 307 | − u8 data[]; | |
| 308 | −} __packed; | |
| 309 | − | |
| 310 | 294 | struct pn533_cmd_jump_dep_response { |
| 311 | 295 | u8 status; |
| 312 | 296 | u8 tg; |
| @@ -329,32 +313,13 @@ struct pn533_cmd_jump_dep_response { · 16 unmodified lines | ||
| 329 | 313 | #define PN533_INIT_TARGET_RESP_ACTIVE 0x1 |
| 330 | 314 | #define PN533_INIT_TARGET_RESP_DEP 0x4 |
| 331 | 315 | |
| 332 | −struct pn533_cmd_init_target { | |
| 333 | − u8 mode; | |
| 334 | − u8 mifare[6]; | |
| 335 | − u8 felica[18]; | |
| 336 | − u8 nfcid3[10]; | |
| 337 | − u8 gb_len; | |
| 338 | − u8 gb[]; | |
| 339 | −} __packed; | |
| 340 | − | |
| 341 | −struct pn533_cmd_init_target_response { | |
| 342 | − u8 mode; | |
| 343 | − u8 cmd[]; | |
| 344 | −} __packed; | |
| 345 | − | |
| 346 | 316 | struct pn533 { |
| 347 | 317 | struct usb_device *udev; |
| 348 | 318 | struct usb_interface *interface; |
| 349 | 319 | struct nfc_dev *nfc_dev; |
| 350 | 320 | |
| 351 | 321 | struct urb *out_urb; |
| 352 | − int out_maxlen; | |
| 353 | − struct pn533_frame *out_frame; | |
| 354 | − | |
| 355 | 322 | struct urb *in_urb; |
| 356 | − int in_maxlen; | |
| 357 | − struct pn533_frame *in_frame; | |
| 358 | 323 | |
| 359 | 324 | struct sk_buff_head resp_q; |
| 360 | 325 | |
| @@ -365,12 +330,12 @@ struct pn533 { · 4 unmodified lines | ||
| 365 | 330 | struct work_struct mi_work; |
| 366 | 331 | struct work_struct tg_work; |
| 367 | 332 | struct timer_list listen_timer; |
| 368 | − struct pn533_frame *wq_in_frame; | |
| 369 | 333 | int wq_in_error; |
| 370 | 334 | int cancel_listen; |
| 371 | 335 | |
| 372 | 336 | pn533_cmd_complete_t cmd_complete; |
| 373 | 337 | void *cmd_complete_arg; |
| 338 | + void *cmd_complete_mi_arg; | |
| 374 | 339 | struct mutex cmd_lock; |
| 375 | 340 | u8 cmd; |
| 376 | 341 | |
| @@ -391,16 +356,17 @@ struct pn533 { · 14 unmodified lines | ||
| 391 | 356 | |
| 392 | 357 | struct list_head cmd_queue; |
| 393 | 358 | u8 cmd_pending; |
| 359 | + | |
| 360 | + struct pn533_frame_ops *ops; | |
| 394 | 361 | }; |
| 395 | 362 | |
| 396 | 363 | struct pn533_cmd { |
| 397 | 364 | struct list_head queue; |
| 398 | − struct pn533_frame *out_frame; | |
| 399 | − struct pn533_frame *in_frame; | |
| 400 | − int in_frame_len; | |
| 401 | − pn533_cmd_complete_t cmd_complete; | |
| 365 | + u8 cmd_code; | |
| 366 | + struct sk_buff *req; | |
| 367 | + struct sk_buff *resp; | |
| 368 | + int resp_len; | |
| 402 | 369 | void *arg; |
| 403 | − gfp_t flags; | |
| 404 | 370 | }; |
| 405 | 371 | |
| 406 | 372 | struct pn533_frame { |
| @@ -411,6 +377,22 @@ struct pn533_frame { · 4 unmodified lines | ||
| 411 | 377 | u8 data[]; |
| 412 | 378 | } __packed; |
| 413 | 379 | |
| 380 | +struct pn533_frame_ops { | |
| 381 | + void (*tx_frame_init)(void *frame, u8 cmd_code); | |
| 382 | + void (*tx_frame_finish)(void *frame); | |
| 383 | + void (*tx_update_payload_len)(void *frame, int len); | |
| 384 | + int tx_header_len; | |
| 385 | + int tx_tail_len; | |
| 386 | + | |
| 387 | + bool (*rx_is_frame_valid)(void *frame); | |
| 388 | + int (*rx_frame_size)(void *frame); | |
| 389 | + int rx_header_len; | |
| 390 | + int rx_tail_len; | |
| 391 | + | |
| 392 | + int max_payload_len; | |
| 393 | + u8 (*get_cmd_code)(void *frame); | |
| 394 | +}; | |
| 395 | + | |
| 414 | 396 | /* The rule: value + checksum = 0 */ |
| 415 | 397 | static inline u8 pn533_checksum(u8 value) |
| 416 | 398 | { |
| @@ -429,37 +411,21 @@ static u8 pn533_data_checksum(u8 *data, int datalen) · 12 unmodified lines | ||
| 429 | 411 | return pn533_checksum(sum); |
| 430 | 412 | } |
| 431 | 413 | |
| 432 | −/** | |
| 433 | − * pn533_tx_frame_ack - create a ack frame | |
| 434 | − * @frame: The frame to be set as ack | |
| 435 | − * | |
| 436 | − * Ack is different type of standard frame. As a standard frame, it has | |
| 437 | − * preamble and start_frame. However the checksum of this frame must fail, | |
| 438 | − * i.e. datalen + datalen_checksum must NOT be zero. When the checksum test | |
| 439 | − * fails and datalen = 0 and datalen_checksum = 0xFF, the frame is a ack. | |
| 440 | − * After datalen_checksum field, the postamble is placed. | |
| 441 | − */ | |
| 442 | −static void pn533_tx_frame_ack(struct pn533_frame *frame) | |
| 414 | +static void pn533_tx_frame_init(void *_frame, u8 cmd_code) | |
| 443 | 415 | { |
| 444 | − frame->preamble = 0; | |
| 445 | − frame->start_frame = cpu_to_be16(PN533_SOF); | |
| 446 | − frame->datalen = 0; | |
| 447 | − frame->datalen_checksum = 0xFF; | |
| 448 | − /* data[0] is used as postamble */ | |
| 449 | − frame->data[0] = 0; | |
| 450 | −} | |
| 416 | + struct pn533_frame *frame = _frame; | |
| 451 | 417 | |
| 452 | −static void pn533_tx_frame_init(struct pn533_frame *frame, u8 cmd) | |
| 453 | −{ | |
| 454 | 418 | frame->preamble = 0; |
| 455 | 419 | frame->start_frame = cpu_to_be16(PN533_SOF); |
| 456 | 420 | PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT; |
| 457 | − PN533_FRAME_CMD(frame) = cmd; | |
| 421 | + PN533_FRAME_CMD(frame) = cmd_code; | |
| 458 | 422 | frame->datalen = 2; |
| 459 | 423 | } |
| 460 | 424 | |
| 461 | −static void pn533_tx_frame_finish(struct pn533_frame *frame) | |
| 425 | +static void pn533_tx_frame_finish(void *_frame) | |
| 462 | 426 | { |
| 427 | + struct pn533_frame *frame = _frame; | |
| 428 | + | |
| 463 | 429 | frame->datalen_checksum = pn533_checksum(frame->datalen); |
| 464 | 430 | |
| 465 | 431 | PN533_FRAME_CHECKSUM(frame) = |
| @@ -468,9 +434,17 @@ static void pn533_tx_frame_finish(struct pn533_frame *frame) · 2 unmodified lines | ||
| 468 | 434 | PN533_FRAME_POSTAMBLE(frame) = 0; |
| 469 | 435 | } |
| 470 | 436 | |
| 471 | −static bool pn533_rx_frame_is_valid(struct pn533_frame *frame) | |
| 437 | +static void pn533_tx_update_payload_len(void *_frame, int len) | |
| 438 | +{ | |
| 439 | + struct pn533_frame *frame = _frame; | |
| 440 | + | |
| 441 | + frame->datalen += len; | |
| 442 | +} | |
| 443 | + | |
| 444 | +static bool pn533_rx_frame_is_valid(void *_frame) | |
| 472 | 445 | { |
| 473 | 446 | u8 checksum; |
| 447 | + struct pn533_frame *frame = _frame; | |
| 474 | 448 | |
| 475 | 449 | if (frame->start_frame != cpu_to_be16(PN533_SOF)) |
| 476 | 450 | return false; |
| @@ -497,28 +471,48 @@ static bool pn533_rx_frame_is_ack(struct pn533_frame *frame) · 20 unmodified lines | ||
| 497 | 471 | return true; |
| 498 | 472 | } |
| 499 | 473 | |
| 500 | −static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd) | |
| 474 | +static inline int pn533_rx_frame_size(void *frame) | |
| 475 | +{ | |
| 476 | + struct pn533_frame *f = frame; | |
| 477 | + | |
| 478 | + return sizeof(struct pn533_frame) + f->datalen + PN533_FRAME_TAIL_LEN; | |
| 479 | +} | |
| 480 | + | |
| 481 | +static u8 pn533_get_cmd_code(void *frame) | |
| 482 | +{ | |
| 483 | + struct pn533_frame *f = frame; | |
| 484 | + | |
| 485 | + return PN533_FRAME_CMD(f); | |
| 486 | +} | |
| 487 | + | |
| 488 | +struct pn533_frame_ops pn533_std_frame_ops = { | |
| 489 | + .tx_frame_init = pn533_tx_frame_init, | |
| 490 | + .tx_frame_finish = pn533_tx_frame_finish, | |
| 491 | + .tx_update_payload_len = pn533_tx_update_payload_len, | |
| 492 | + .tx_header_len = PN533_FRAME_HEADER_LEN, | |
| 493 | + .tx_tail_len = PN533_FRAME_TAIL_LEN, | |
| 494 | + | |
| 495 | + .rx_is_frame_valid = pn533_rx_frame_is_valid, | |
| 496 | + .rx_frame_size = pn533_rx_frame_size, | |
| 497 | + .rx_header_len = PN533_FRAME_HEADER_LEN, | |
| 498 | + .rx_tail_len = PN533_FRAME_TAIL_LEN, | |
| 499 | + | |
| 500 | + .max_payload_len = PN533_FRAME_MAX_PAYLOAD_LEN, | |
| 501 | + .get_cmd_code = pn533_get_cmd_code, | |
| 502 | +}; | |
| 503 | + | |
| 504 | +static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame) | |
| 501 | 505 | { |
| 502 | − return (PN533_FRAME_CMD(frame) == PN533_CMD_RESPONSE(cmd)); | |
| 506 | + return (dev->ops->get_cmd_code(frame) == PN533_CMD_RESPONSE(dev->cmd)); | |
| 503 | 507 | } |
| 504 | 508 | |
| 505 | 509 | |
| 506 | 510 | static void pn533_wq_cmd_complete(struct work_struct *work) |
| 507 | 511 | { |
| 508 | 512 | struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work); |
| 509 | − struct pn533_frame *in_frame; | |
| 510 | 513 | int rc; |
| 511 | 514 | |
| 512 | − in_frame = dev->wq_in_frame; | |
| 513 | − | |
| 514 | − if (dev->wq_in_error) | |
| 515 | − rc = dev->cmd_complete(dev, dev->cmd_complete_arg, NULL, | |
| 516 | − dev->wq_in_error); | |
| 517 | − else | |
| 518 | − rc = dev->cmd_complete(dev, dev->cmd_complete_arg, | |
| 519 | − PN533_FRAME_CMD_PARAMS_PTR(in_frame), | |
| 520 | − PN533_FRAME_CMD_PARAMS_LEN(in_frame)); | |
| 521 | − | |
| 515 | + rc = dev->cmd_complete(dev, dev->cmd_complete_arg, dev->wq_in_error); | |
| 522 | 516 | if (rc != -EINPROGRESS) |
| 523 | 517 | queue_work(dev->wq, &dev->cmd_work); |
| 524 | 518 | } |
| @@ -526,46 +520,47 @@ static void pn533_wq_cmd_complete(struct work_struct *work) · 1 unmodified line | ||
| 526 | 520 | static void pn533_recv_response(struct urb *urb) |
| 527 | 521 | { |
| 528 | 522 | struct pn533 *dev = urb->context; |
| 529 | − struct pn533_frame *in_frame; | |
| 530 | − | |
| 531 | − dev->wq_in_frame = NULL; | |
| 523 | + u8 *in_frame; | |
| 532 | 524 | |
| 533 | 525 | switch (urb->status) { |
| 534 | 526 | case 0: |
| 535 | − /* success */ | |
| 536 | − break; | |
| 527 | + break; /* success */ | |
| 537 | 528 | case -ECONNRESET: |
| 538 | 529 | case -ENOENT: |
| 539 | − case -ESHUTDOWN: | |
| 540 | − nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with" | |
| 541 | − " status: %d", urb->status); | |
| 530 | + nfc_dev_dbg(&dev->interface->dev, | |
| 531 | + "The urb has been canceled (status %d)", | |
| 532 | + urb->status); | |
| 542 | 533 | dev->wq_in_error = urb->status; |
| 543 | 534 | goto sched_wq; |
| 535 | + break; | |
| 536 | + case -ESHUTDOWN: | |
| 544 | 537 | default: |
| 545 | − nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:" | |
| 546 | − " %d", urb->status); | |
| 538 | + nfc_dev_err(&dev->interface->dev, | |
| 539 | + "Urb failure (status %d)", urb->status); | |
| 547 | 540 | dev->wq_in_error = urb->status; |
| 548 | 541 | goto sched_wq; |
| 549 | 542 | } |
| 550 | 543 | |
| 551 | 544 | in_frame = dev->in_urb->transfer_buffer; |
| 552 | 545 | |
| 553 | − if (!pn533_rx_frame_is_valid(in_frame)) { | |
| 546 | + nfc_dev_dbg(&dev->interface->dev, "Received a frame."); | |
| 547 | + print_hex_dump(KERN_DEBUG, "PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, | |
| 548 | + in_frame, dev->ops->rx_frame_size(in_frame), false); | |
| 549 | + | |
| 550 | + if (!dev->ops->rx_is_frame_valid(in_frame)) { | |
| 554 | 551 | nfc_dev_err(&dev->interface->dev, "Received an invalid frame"); |
| 555 | 552 | dev->wq_in_error = -EIO; |
| 556 | 553 | goto sched_wq; |
| 557 | 554 | } |
| 558 | 555 | |
| 559 | − if (!pn533_rx_frame_is_cmd_response(in_frame, dev->cmd)) { | |
| 560 | − nfc_dev_err(&dev->interface->dev, "The received frame is not " | |
| 561 | − "response to the last command"); | |
| 556 | + if (!pn533_rx_frame_is_cmd_response(dev, in_frame)) { | |
| 557 | + nfc_dev_err(&dev->interface->dev, | |
| 558 | + "It it not the response to the last command"); | |
| 562 | 559 | dev->wq_in_error = -EIO; |
| 563 | 560 | goto sched_wq; |
| 564 | 561 | } |
| 565 | 562 | |
| 566 | − nfc_dev_dbg(&dev->interface->dev, "Received a valid frame"); | |
| 567 | 563 | dev->wq_in_error = 0; |
| 568 | − dev->wq_in_frame = in_frame; | |
| 569 | 564 | |
| 570 | 565 | sched_wq: |
| 571 | 566 | queue_work(dev->wq, &dev->cmd_complete_work); |
| @@ -586,18 +581,19 @@ static void pn533_recv_ack(struct urb *urb) · 14 unmodified lines | ||
| 586 | 581 | |
| 587 | 582 | switch (urb->status) { |
| 588 | 583 | case 0: |
| 589 | − /* success */ | |
| 590 | − break; | |
| 584 | + break; /* success */ | |
| 591 | 585 | case -ECONNRESET: |
| 592 | 586 | case -ENOENT: |
| 593 | − case -ESHUTDOWN: | |
| 594 | − nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with" | |
| 595 | − " status: %d", urb->status); | |
| 587 | + nfc_dev_dbg(&dev->interface->dev, | |
| 588 | + "The urb has been stopped (status %d)", | |
| 589 | + urb->status); | |
| 596 | 590 | dev->wq_in_error = urb->status; |
| 597 | 591 | goto sched_wq; |
| 592 | + break; | |
| 593 | + case -ESHUTDOWN: | |
| 598 | 594 | default: |
| 599 | − nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:" | |
| 600 | − " %d", urb->status); | |
| 595 | + nfc_dev_err(&dev->interface->dev, | |
| 596 | + "Urb failure (status %d)", urb->status); | |
| 601 | 597 | dev->wq_in_error = urb->status; |
| 602 | 598 | goto sched_wq; |
| 603 | 599 | } |
| @@ -610,12 +606,10 @@ static void pn533_recv_ack(struct urb *urb) · 6 unmodified lines | ||
| 610 | 606 | goto sched_wq; |
| 611 | 607 | } |
| 612 | 608 | |
| 613 | − nfc_dev_dbg(&dev->interface->dev, "Received a valid ack"); | |
| 614 | − | |
| 615 | 609 | rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC); |
| 616 | 610 | if (rc) { |
| 617 | − nfc_dev_err(&dev->interface->dev, "usb_submit_urb failed with" | |
| 618 | − " result %d", rc); | |
| 611 | + nfc_dev_err(&dev->interface->dev, | |
| 612 | + "usb_submit_urb failed with result %d", rc); | |
| 619 | 613 | dev->wq_in_error = rc; |
| 620 | 614 | goto sched_wq; |
| 621 | 615 | } |
| @@ -623,7 +617,6 @@ static void pn533_recv_ack(struct urb *urb) · 1 unmodified line | ||
| 623 | 617 | return; |
| 624 | 618 | |
| 625 | 619 | sched_wq: |
| 626 | − dev->wq_in_frame = NULL; | |
| 627 | 620 | queue_work(dev->wq, &dev->cmd_complete_work); |
| 628 | 621 | } |
| 629 | 622 | |
| @@ -636,47 +629,46 @@ static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) · 6 unmodified lines | ||
| 636 | 629 | |
| 637 | 630 | static int pn533_send_ack(struct pn533 *dev, gfp_t flags) |
| 638 | 631 | { |
| 632 | + u8 ack[PN533_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; | |
| 633 | + /* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */ | |
| 639 | 634 | int rc; |
| 640 | 635 | |
| 641 | 636 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
| 642 | 637 | |
| 643 | − pn533_tx_frame_ack(dev->out_frame); | |
| 644 | − | |
| 645 | − dev->out_urb->transfer_buffer = dev->out_frame; | |
| 646 | − dev->out_urb->transfer_buffer_length = PN533_FRAME_ACK_SIZE; | |
| 638 | + dev->out_urb->transfer_buffer = ack; | |
| 639 | + dev->out_urb->transfer_buffer_length = sizeof(ack); | |
| 647 | 640 | rc = usb_submit_urb(dev->out_urb, flags); |
| 648 | 641 | |
| 649 | 642 | return rc; |
| 650 | 643 | } |
| 651 | 644 | |
| 652 | −static int __pn533_send_cmd_frame_async(struct pn533 *dev, | |
| 653 | − struct pn533_frame *out_frame, | |
| 654 | − struct pn533_frame *in_frame, | |
| 655 | − int in_frame_len, | |
| 645 | +static int __pn533_send_frame_async(struct pn533 *dev, | |
| 646 | + struct sk_buff *out, | |
| 647 | + struct sk_buff *in, | |
| 648 | + int in_len, | |
| 656 | 649 | pn533_cmd_complete_t cmd_complete, |
| 657 | − void *arg, gfp_t flags) | |
| 650 | + void *arg) | |
| 658 | 651 | { |
| 659 | 652 | int rc; |
| 660 | 653 | |
| 661 | − nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", | |
| 662 | − PN533_FRAME_CMD(out_frame)); | |
| 663 | − | |
| 664 | − dev->cmd = PN533_FRAME_CMD(out_frame); | |
| 654 | + dev->cmd = dev->ops->get_cmd_code(out->data); | |
| 665 | 655 | dev->cmd_complete = cmd_complete; |
| 666 | 656 | dev->cmd_complete_arg = arg; |
| 667 | 657 | |
| 668 | − dev->out_urb->transfer_buffer = out_frame; | |
| 669 | − dev->out_urb->transfer_buffer_length = | |
| 670 | − PN533_FRAME_SIZE(out_frame); | |
| 658 | + dev->out_urb->transfer_buffer = out->data; | |
| 659 | + dev->out_urb->transfer_buffer_length = out->len; | |
| 671 | 660 | |
| 672 | − dev->in_urb->transfer_buffer = in_frame; | |
| 673 | − dev->in_urb->transfer_buffer_length = in_frame_len; | |
| 661 | + dev->in_urb->transfer_buffer = in->data; | |
| 662 | + dev->in_urb->transfer_buffer_length = in_len; | |
| 674 | 663 | |
| 675 | − rc = usb_submit_urb(dev->out_urb, flags); | |
| 664 | + print_hex_dump(KERN_DEBUG, "PN533 TX: ", DUMP_PREFIX_NONE, 16, 1, | |
| 665 | + out->data, out->len, false); | |
| 666 | + | |
| 667 | + rc = usb_submit_urb(dev->out_urb, GFP_KERNEL); | |
| 676 | 668 | if (rc) |
| 677 | 669 | return rc; |
| 678 | 670 | |
| 679 | − rc = pn533_submit_urb_for_ack(dev, flags); | |
| 671 | + rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL); | |
| 680 | 672 | if (rc) |
| 681 | 673 | goto error; |
| 682 | 674 | |
| @@ -687,146 +679,325 @@ error: · 4 unmodified lines | ||
| 687 | 679 | return rc; |
| 688 | 680 | } |
| 689 | 681 | |
| 690 | −static void pn533_wq_cmd(struct work_struct *work) | |
| 682 | +static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code, | |
| 683 | + struct sk_buff *skb) | |
| 691 | 684 | { |
| 692 | − struct pn533 *dev = container_of(work, struct pn533, cmd_work); | |
| 693 | − struct pn533_cmd *cmd; | |
| 685 | + /* payload is already there, just update datalen */ | |
| 686 | + int payload_len = skb->len; | |
| 687 | + struct pn533_frame_ops *ops = dev->ops; | |
| 694 | 688 | |
| 695 | − mutex_lock(&dev->cmd_lock); | |
| 696 | 689 | |
| 697 | − if (list_empty(&dev->cmd_queue)) { | |
| 698 | − dev->cmd_pending = 0; | |
| 699 | − mutex_unlock(&dev->cmd_lock); | |
| 700 | − return; | |
| 701 | − } | |
| 690 | + skb_push(skb, ops->tx_header_len); | |
| 691 | + skb_put(skb, ops->tx_tail_len); | |
| 702 | 692 | |
| 703 | − cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); | |
| 693 | + ops->tx_frame_init(skb->data, cmd_code); | |
| 694 | + ops->tx_update_payload_len(skb->data, payload_len); | |
| 695 | + ops->tx_frame_finish(skb->data); | |
| 696 | +} | |
| 704 | 697 | |
| 705 | − list_del(&cmd->queue); | |
| 698 | +struct pn533_send_async_complete_arg { | |
| 699 | + pn533_send_async_complete_t complete_cb; | |
| 700 | + void *complete_cb_context; | |
| 701 | + struct sk_buff *resp; | |
| 702 | + struct sk_buff *req; | |
| 703 | +}; | |
| 706 | 704 | |
| 707 | − mutex_unlock(&dev->cmd_lock); | |
| 705 | +static int pn533_send_async_complete(struct pn533 *dev, void *_arg, int status) | |
| 706 | +{ | |
| 707 | + struct pn533_send_async_complete_arg *arg = _arg; | |
| 708 | 708 | |
| 709 | − __pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame, | |
| 710 | − cmd->in_frame_len, cmd->cmd_complete, | |
| 711 | − cmd->arg, cmd->flags); | |
| 709 | + struct sk_buff *req = arg->req; | |
| 710 | + struct sk_buff *resp = arg->resp; | |
| 712 | 711 | |
| 713 | − kfree(cmd); | |
| 712 | + int rc; | |
| 713 | + | |
| 714 | + dev_kfree_skb(req); | |
| 715 | + | |
| 716 | + if (status < 0) { | |
| 717 | + arg->complete_cb(dev, arg->complete_cb_context, | |
| 718 | + ERR_PTR(status)); | |
| 719 | + dev_kfree_skb(resp); | |
| 720 | + kfree(arg); | |
| 721 | + return status; | |
| 722 | + } | |
| 723 | + | |
| 724 | + skb_put(resp, dev->ops->rx_frame_size(resp->data)); | |
| 725 | + skb_pull(resp, dev->ops->rx_header_len); | |
| 726 | + skb_trim(resp, resp->len - dev->ops->rx_tail_len); | |
| 727 | + | |
| 728 | + rc = arg->complete_cb(dev, arg->complete_cb_context, resp); | |
| 729 | + | |
| 730 | + kfree(arg); | |
| 731 | + return rc; | |
| 714 | 732 | } |
| 715 | 733 | |
| 716 | −static int pn533_send_cmd_frame_async(struct pn533 *dev, | |
| 717 | − struct pn533_frame *out_frame, | |
| 718 | − struct pn533_frame *in_frame, | |
| 719 | − int in_frame_len, | |
| 720 | − pn533_cmd_complete_t cmd_complete, | |
| 721 | − void *arg, gfp_t flags) | |
| 734 | +static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, | |
| 735 | + struct sk_buff *req, struct sk_buff *resp, | |
| 736 | + int resp_len, | |
| 737 | + pn533_send_async_complete_t complete_cb, | |
| 738 | + void *complete_cb_context) | |
| 722 | 739 | { |
| 723 | 740 | struct pn533_cmd *cmd; |
| 741 | + struct pn533_send_async_complete_arg *arg; | |
| 724 | 742 | int rc = 0; |
| 725 | 743 | |
| 726 | − nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | |
| 744 | + nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", cmd_code); | |
| 745 | + | |
| 746 | + arg = kzalloc(sizeof(*arg), GFP_KERNEL); | |
| 747 | + if (!arg) | |
| 748 | + return -ENOMEM; | |
| 749 | + | |
| 750 | + arg->complete_cb = complete_cb; | |
| 751 | + arg->complete_cb_context = complete_cb_context; | |
| 752 | + arg->resp = resp; | |
| 753 | + arg->req = req; | |
| 754 | + | |
| 755 | + pn533_build_cmd_frame(dev, cmd_code, req); | |
| 727 | 756 | |
| 728 | 757 | mutex_lock(&dev->cmd_lock); |
| 729 | 758 | |
| 730 | 759 | if (!dev->cmd_pending) { |
| 731 | − rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame, | |
| 732 | − in_frame_len, cmd_complete, | |
| 733 | − arg, flags); | |
| 734 | − if (!rc) | |
| 735 | − dev->cmd_pending = 1; | |
| 760 | + rc = __pn533_send_frame_async(dev, req, resp, resp_len, | |
| 761 | + pn533_send_async_complete, arg); | |
| 762 | + if (rc) | |
| 763 | + goto error; | |
| 736 | 764 | |
| 765 | + dev->cmd_pending = 1; | |
| 737 | 766 | goto unlock; |
| 738 | 767 | } |
| 739 | 768 | |
| 740 | − nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__); | |
| 769 | + nfc_dev_dbg(&dev->interface->dev, "%s Queueing command 0x%x", __func__, | |
| 770 | + cmd_code); | |
| 741 | 771 | |
| 742 | − cmd = kzalloc(sizeof(struct pn533_cmd), flags); | |
| 772 | + cmd = kzalloc(sizeof(struct pn533_cmd), GFP_KERNEL); | |
| 743 | 773 | if (!cmd) { |
| 744 | 774 | rc = -ENOMEM; |
| 745 | − goto unlock; | |
| 775 | + goto error; | |
| 746 | 776 | } |
| 747 | 777 | |
| 748 | 778 | INIT_LIST_HEAD(&cmd->queue); |
| 749 | − cmd->out_frame = out_frame; | |
| 750 | − cmd->in_frame = in_frame; | |
| 751 | − cmd->in_frame_len = in_frame_len; | |
| 752 | − cmd->cmd_complete = cmd_complete; | |
| 779 | + cmd->cmd_code = cmd_code; | |
| 780 | + cmd->req = req; | |
| 781 | + cmd->resp = resp; | |
| 782 | + cmd->resp_len = resp_len; | |
| 753 | 783 | cmd->arg = arg; |
| 754 | − cmd->flags = flags; | |
| 755 | 784 | |
| 756 | 785 | list_add_tail(&cmd->queue, &dev->cmd_queue); |
| 757 | 786 | |
| 787 | + goto unlock; | |
| 788 | + | |
| 789 | +error: | |
| 790 | + kfree(arg); | |
| 758 | 791 | unlock: |
| 759 | 792 | mutex_unlock(&dev->cmd_lock); |
| 793 | + return rc; | |
| 794 | +} | |
| 795 | + | |
| 796 | +static int pn533_send_data_async(struct pn533 *dev, u8 cmd_code, | |
| 797 | + struct sk_buff *req, | |
| 798 | + pn533_send_async_complete_t complete_cb, | |
| 799 | + void *complete_cb_context) | |
| 800 | +{ | |
| 801 | + struct sk_buff *resp; | |
| 802 | + int rc; | |
| 803 | + int resp_len = dev->ops->rx_header_len + | |
| 804 | + dev->ops->max_payload_len + | |
| 805 | + dev->ops->rx_tail_len; | |
| 806 | + | |
| 807 | + resp = nfc_alloc_recv_skb(resp_len, GFP_KERNEL); | |
| 808 | + if (!resp) | |
| 809 | + return -ENOMEM; | |
| 810 | + | |
| 811 | + rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb, | |
| 812 | + complete_cb_context); | |
| 813 | + if (rc) | |
| 814 | + dev_kfree_skb(resp); | |
| 760 | 815 | |
| 761 | 816 | return rc; |
| 762 | 817 | } |
| 763 | 818 | |
| 764 | −struct pn533_sync_cmd_response { | |
| 819 | +static int pn533_send_cmd_async(struct pn533 *dev, u8 cmd_code, | |
| 820 | + struct sk_buff *req, | |
| 821 | + pn533_send_async_complete_t complete_cb, | |
| 822 | + void *complete_cb_context) | |
| 823 | +{ | |
| 824 | + struct sk_buff *resp; | |
| 765 | 825 | int rc; |
| 766 | − struct completion done; | |
| 767 | −}; | |
| 826 | + int resp_len = dev->ops->rx_header_len + | |
| 827 | + dev->ops->max_payload_len + | |
| 828 | + dev->ops->rx_tail_len; | |
| 829 | + | |
| 830 | + resp = alloc_skb(resp_len, GFP_KERNEL); | |
| 831 | + if (!resp) | |
| 832 | + return -ENOMEM; | |
| 833 | + | |
| 834 | + rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb, | |
| 835 | + complete_cb_context); | |
| 836 | + if (rc) | |
| 837 | + dev_kfree_skb(resp); | |
| 768 | 838 | |
| 769 | −static int pn533_sync_cmd_complete(struct pn533 *dev, void *_arg, | |
| 770 | − u8 *params, int params_len) | |
| 839 | + return rc; | |
| 840 | +} | |
| 841 | + | |
| 842 | +/* | |
| 843 | + * pn533_send_cmd_direct_async | |
| 844 | + * | |
| 845 | + * The function sends a piority cmd directly to the chip omiting the cmd | |
| 846 | + * queue. It's intended to be used by chaining mechanism of received responses | |
| 847 | + * where the host has to request every single chunk of data before scheduling | |
| 848 | + * next cmd from the queue. | |
| 849 | + */ | |
| 850 | +static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, | |
| 851 | + struct sk_buff *req, | |
| 852 | + pn533_send_async_complete_t complete_cb, | |
| 853 | + void *complete_cb_context) | |
| 771 | 854 | { |
| 772 | − struct pn533_sync_cmd_response *arg = _arg; | |
| 855 | + struct pn533_send_async_complete_arg *arg; | |
| 856 | + struct sk_buff *resp; | |
| 857 | + int rc; | |
| 858 | + int resp_len = dev->ops->rx_header_len + | |
| 859 | + dev->ops->max_payload_len + | |
| 860 | + dev->ops->rx_tail_len; | |
| 773 | 861 | |
| 774 | − nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | |
| 862 | + resp = alloc_skb(resp_len, GFP_KERNEL); | |
| 863 | + if (!resp) | |
| 864 | + return -ENOMEM; | |
| 865 | + | |
| 866 | + arg = kzalloc(sizeof(*arg), GFP_KERNEL); | |
| 867 | + if (!arg) { | |
| 868 | + dev_kfree_skb(resp); | |
| 869 | + return -ENOMEM; | |
| 870 | + } | |
| 775 | 871 | |
| 776 | − arg->rc = 0; | |
| 872 | + arg->complete_cb = complete_cb; | |
| 873 | + arg->complete_cb_context = complete_cb_context; | |
| 874 | + arg->resp = resp; | |
| 875 | + arg->req = req; | |
| 777 | 876 | |
| 778 | − if (params_len < 0) /* error */ | |
| 779 | − arg->rc = params_len; | |
| 877 | + pn533_build_cmd_frame(dev, cmd_code, req); | |
| 780 | 878 | |
| 879 | + rc = __pn533_send_frame_async(dev, req, resp, resp_len, | |
| 880 | + pn533_send_async_complete, arg); | |
| 881 | + if (rc < 0) { | |
| 882 | + dev_kfree_skb(resp); | |
| 883 | + kfree(arg); | |
| 884 | + } | |
| 885 | + | |
| 886 | + return rc; | |
| 887 | +} | |
| 888 | + | |
| 889 | +static void pn533_wq_cmd(struct work_struct *work) | |
| 890 | +{ | |
| 891 | + struct pn533 *dev = container_of(work, struct pn533, cmd_work); | |
| 892 | + struct pn533_cmd *cmd; | |
| 893 | + | |
| 894 | + mutex_lock(&dev->cmd_lock); | |
| 895 | + | |
| 896 | + if (list_empty(&dev->cmd_queue)) { | |
| 897 | + dev->cmd_pending = 0; | |
| 898 | + mutex_unlock(&dev->cmd_lock); | |
| 899 | + return; | |
| 900 | + } | |
| 901 | + | |
| 902 | + cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); | |
| 903 | + | |
| 904 | + list_del(&cmd->queue); | |
| 905 | + | |
| 906 | + mutex_unlock(&dev->cmd_lock); | |
| 907 | + | |
| 908 | + __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len, | |
| 909 | + pn533_send_async_complete, cmd->arg); | |
| 910 | + | |
| 911 | + kfree(cmd); | |
| 912 | +} | |
| 913 | + | |
| 914 | +struct pn533_sync_cmd_response { | |
| 915 | + struct sk_buff *resp; | |
| 916 | + struct completion done; | |
| 917 | +}; | |
| 918 | + | |
| 919 | +static int pn533_send_sync_complete(struct pn533 *dev, void *_arg, | |
| 920 | + struct sk_buff *resp) | |
| 921 | +{ | |
| 922 | + struct pn533_sync_cmd_response *arg = _arg; | |
| 923 | + | |
| 924 | + arg->resp = resp; | |
| 781 | 925 | complete(&arg->done); |
| 782 | 926 | |
| 783 | 927 | return 0; |
| 784 | 928 | } |
| 785 | 929 | |
| 786 | −static int pn533_send_cmd_frame_sync(struct pn533 *dev, | |
| 787 | − struct pn533_frame *out_frame, | |
| 788 | − struct pn533_frame *in_frame, | |
| 789 | − int in_frame_len) | |
| 930 | +/* pn533_send_cmd_sync | |
| 931 | + * | |
| 932 | + * Please note the req parameter is freed inside the function to | |
| 933 | + * limit a number of return value interpretations by the caller. | |
| 934 | + * | |
| 935 | + * 1. negative in case of error during TX path -> req should be freed | |
| 936 | + * | |
| 937 | + * 2. negative in case of error during RX path -> req should not be freed | |
| 938 | + * as it's been already freed at the begining of RX path by | |
| 939 | + * async_complete_cb. | |
| 940 | + * | |
| 941 | + * 3. valid pointer in case of succesfult RX path | |
| 942 | + * | |
| 943 | + * A caller has to check a return value with IS_ERR macro. If the test pass, | |
| 944 | + * the returned pointer is valid. | |
| 945 | + * | |
| 946 | + * */ | |
| 947 | +static struct sk_buff *pn533_send_cmd_sync(struct pn533 *dev, u8 cmd_code, | |
| 948 | + struct sk_buff *req) | |
| 790 | 949 | { |
| 791 | 950 | int rc; |
| 792 | 951 | struct pn533_sync_cmd_response arg; |
| 793 | 952 | |
| 794 | − nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | |
| 795 | − | |
| 796 | 953 | init_completion(&arg.done); |
| 797 | 954 | |
| 798 | − rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, in_frame_len, | |
| 799 | − pn533_sync_cmd_complete, &arg, GFP_KERNEL); | |
| 800 | − if (rc) | |
| 801 | − return rc; | |
| 955 | + rc = pn533_send_cmd_async(dev, cmd_code, req, | |
| 956 | + pn533_send_sync_complete, &arg); | |
| 957 | + if (rc) { | |
| 958 | + dev_kfree_skb(req); | |
| 959 | + return ERR_PTR(rc); | |
| 960 | + } | |
| 802 | 961 | |
| 803 | 962 | wait_for_completion(&arg.done); |
| 804 | 963 | |
| 805 | − return arg.rc; | |
| 964 | + return arg.resp; | |
| 806 | 965 | } |
| 807 | 966 | |
| 808 | 967 | static void pn533_send_complete(struct urb *urb) |
| 809 | 968 | { |
| 810 | 969 | struct pn533 *dev = urb->context; |
| 811 | 970 | |
| 812 | − nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | |
| 813 | − | |
| 814 | 971 | switch (urb->status) { |
| 815 | 972 | case 0: |
| 816 | − /* success */ | |
| 817 | − break; | |
| 973 | + break; /* success */ | |
| 818 | 974 | case -ECONNRESET: |
| 819 | 975 | case -ENOENT: |
| 820 | − case -ESHUTDOWN: | |
| 821 | − nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with" | |
| 822 | − " status: %d", urb->status); | |
| 976 | + nfc_dev_dbg(&dev->interface->dev, | |
| 977 | + "The urb has been stopped (status %d)", | |
| 978 | + urb->status); | |
| 823 | 979 | break; |
| 980 | + case -ESHUTDOWN: | |
| 824 | 981 | default: |
| 825 | − nfc_dev_dbg(&dev->interface->dev, "Nonzero urb status received:" | |
| 826 | − " %d", urb->status); | |
| 982 | + nfc_dev_err(&dev->interface->dev, | |
| 983 | + "Urb failure (status %d)", urb->status); | |
| 827 | 984 | } |
| 828 | 985 | } |
| 829 | 986 | |
| 987 | +static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size) | |
| 988 | +{ | |
| 989 | + struct sk_buff *skb; | |
| 990 | + | |
| 991 | + skb = alloc_skb(dev->ops->tx_header_len + | |
| 992 | + size + | |
| 993 | + dev->ops->tx_tail_len, GFP_KERNEL); | |
| 994 | + | |
| 995 | + if (skb) | |
| 996 | + skb_reserve(skb, dev->ops->tx_header_len); | |
| 997 | + | |
| 998 | + return skb; | |
| 999 | +} | |
| 1000 | + | |
| 830 | 1001 | struct pn533_target_type_a { |
| 831 | 1002 | __be16 sens_res; |
| 832 | 1003 | u8 sel_res; |
| @@ -867,9 +1038,9 @@ static bool pn533_target_type_a_is_valid(struct pn533_target_type_a *type_a, · 34 unmodified lines | ||
| 867 | 1038 | platconf = PN533_TYPE_A_SENS_RES_PLATCONF(type_a->sens_res); |
| 868 | 1039 | |
| 869 | 1040 | if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL && |
| 870 | − platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) || | |
| 871 | − (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL && | |
| 872 | − platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL)) | |
| 1041 | + platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) || | |
| 1042 | + (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL && | |
| 1043 | + platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL)) | |
| 873 | 1044 | return false; |
| 874 | 1045 | |
| 875 | 1046 | /* Requirements 4.8.2.1, 4.8.2.3, 4.8.2.5 and 4.8.2.7 from NFC Forum */ |
| @@ -884,7 +1055,7 @@ static int pn533_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data, · 8 unmodified lines | ||
| 884 | 1055 | { |
| 885 | 1056 | struct pn533_target_type_a *tgt_type_a; |
| 886 | 1057 | |
| 887 | − tgt_type_a = (struct pn533_target_type_a *) tgt_data; | |
| 1058 | + tgt_type_a = (struct pn533_target_type_a *)tgt_data; | |
| 888 | 1059 | |
| 889 | 1060 | if (!pn533_target_type_a_is_valid(tgt_type_a, tgt_data_len)) |
| 890 | 1061 | return -EPROTO; |
| @@ -942,14 +1113,13 @@ static int pn533_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data, · 51 unmodified lines | ||
| 942 | 1113 | { |
| 943 | 1114 | struct pn533_target_felica *tgt_felica; |
| 944 | 1115 | |
| 945 | − tgt_felica = (struct pn533_target_felica *) tgt_data; | |
| 1116 | + tgt_felica = (struct pn533_target_felica *)tgt_data; | |
| 946 | 1117 | |
| 947 | 1118 | if (!pn533_target_felica_is_valid(tgt_felica, tgt_data_len)) |
| 948 | 1119 | return -EPROTO; |
| 949 | 1120 | |
| 950 | − if (tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1 && | |
| 951 | − tgt_felica->nfcid2[1] == | |
| 952 | − PN533_FELICA_SENSF_NFCID2_DEP_B2) | |
| 1121 | + if ((tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1) && | |
| 1122 | + (tgt_felica->nfcid2[1] == PN533_FELICA_SENSF_NFCID2_DEP_B2)) | |
| 953 | 1123 | nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK; |
| 954 | 1124 | else |
| 955 | 1125 | nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK; |
| @@ -979,9 +1149,9 @@ static bool pn533_target_jewel_is_valid(struct pn533_target_jewel *jewel, · 23 unmodified lines | ||
| 979 | 1149 | platconf = PN533_TYPE_A_SENS_RES_PLATCONF(jewel->sens_res); |
| 980 | 1150 | |
| 981 | 1151 | if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL && |
| 982 | − platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) || | |
| 983 | − (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL && | |
| 984 | − platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL)) | |
| 1152 | + platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) || | |
| 1153 | + (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL && | |
| 1154 | + platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL)) | |
| 985 | 1155 | return false; |
| 986 | 1156 | |
| 987 | 1157 | return true; |
| @@ -992,7 +1162,7 @@ static int pn533_target_found_jewel(struct nfc_target *nfc_tgt, u8 *tgt_data, · 4 unmodified lines | ||
| 992 | 1162 | { |
| 993 | 1163 | struct pn533_target_jewel *tgt_jewel; |
| 994 | 1164 | |
| 995 | − tgt_jewel = (struct pn533_target_jewel *) tgt_data; | |
| 1165 | + tgt_jewel = (struct pn533_target_jewel *)tgt_data; | |
| 996 | 1166 | |
| 997 | 1167 | if (!pn533_target_jewel_is_valid(tgt_jewel, tgt_data_len)) |
| 998 | 1168 | return -EPROTO; |
| @@ -1051,7 +1221,7 @@ static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data, · 52 unmodified lines | ||
| 1051 | 1221 | { |
| 1052 | 1222 | struct pn533_target_type_b *tgt_type_b; |
| 1053 | 1223 | |
| 1054 | − tgt_type_b = (struct pn533_target_type_b *) tgt_data; | |
| 1224 | + tgt_type_b = (struct pn533_target_type_b *)tgt_data; | |
| 1055 | 1225 | |
| 1056 | 1226 | if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len)) |
| 1057 | 1227 | return -EPROTO; |
| @@ -1061,50 +1231,37 @@ static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data, · 3 unmodified lines | ||
| 1061 | 1231 | return 0; |
| 1062 | 1232 | } |
| 1063 | 1233 | |
| 1064 | −struct pn533_poll_response { | |
| 1065 | − u8 nbtg; | |
| 1066 | − u8 tg; | |
| 1067 | − u8 target_data[]; | |
| 1068 | −} __packed; | |
| 1069 | − | |
| 1070 | −static int pn533_target_found(struct pn533 *dev, | |
| 1071 | − struct pn533_poll_response *resp, int resp_len) | |
| 1234 | +static int pn533_target_found(struct pn533 *dev, u8 tg, u8 *tgdata, | |
| 1235 | + int tgdata_len) | |
| 1072 | 1236 | { |
| 1073 | − int target_data_len; | |
| 1074 | 1237 | struct nfc_target nfc_tgt; |
| 1075 | 1238 | int rc; |
| 1076 | 1239 | |
| 1077 | 1240 | nfc_dev_dbg(&dev->interface->dev, "%s - modulation=%d", __func__, |
| 1078 | − dev->poll_mod_curr); | |
| 1241 | + dev->poll_mod_curr); | |
| 1079 | 1242 | |
| 1080 | − if (resp->tg != 1) | |
| 1243 | + if (tg != 1) | |
| 1081 | 1244 | return -EPROTO; |
| 1082 | 1245 | |
| 1083 | 1246 | memset(&nfc_tgt, 0, sizeof(struct nfc_target)); |
| 1084 | 1247 | |
| 1085 | − target_data_len = resp_len - sizeof(struct pn533_poll_response); | |
| 1086 | − | |
| 1087 | 1248 | switch (dev->poll_mod_curr) { |
| 1088 | 1249 | case PN533_POLL_MOD_106KBPS_A: |
| 1089 | − rc = pn533_target_found_type_a(&nfc_tgt, resp->target_data, | |
| 1090 | − target_data_len); | |
| 1250 | + rc = pn533_target_found_type_a(&nfc_tgt, tgdata, tgdata_len); | |
| 1091 | 1251 | break; |
| 1092 | 1252 | case PN533_POLL_MOD_212KBPS_FELICA: |
| 1093 | 1253 | case PN533_POLL_MOD_424KBPS_FELICA: |
| 1094 | − rc = pn533_target_found_felica(&nfc_tgt, resp->target_data, | |
| 1095 | − target_data_len); | |
| 1254 | + rc = pn533_target_found_felica(&nfc_tgt, tgdata, tgdata_len); | |
| 1096 | 1255 | break; |
| 1097 | 1256 | case PN533_POLL_MOD_106KBPS_JEWEL: |
| 1098 | − rc = pn533_target_found_jewel(&nfc_tgt, resp->target_data, | |
| 1099 | − target_data_len); | |
| 1257 | + rc = pn533_target_found_jewel(&nfc_tgt, tgdata, tgdata_len); | |
| 1100 | 1258 | break; |
| 1101 | 1259 | case PN533_POLL_MOD_847KBPS_B: |
| 1102 | − rc = pn533_target_found_type_b(&nfc_tgt, resp->target_data, | |
| 1103 | − target_data_len); | |
| 1260 | + rc = pn533_target_found_type_b(&nfc_tgt, tgdata, tgdata_len); | |
| 1104 | 1261 | break; |
| 1105 | 1262 | default: |
| 1106 | − nfc_dev_err(&dev->interface->dev, "Unknown current poll" | |
| 1107 | − " modulation"); | |
| 1263 | + nfc_dev_err(&dev->interface->dev, | |
| 1264 | + "Unknown current poll modulation"); | |
| 1108 | 1265 | return -EPROTO; |
| 1109 | 1266 | } |
| 1110 | 1267 | |
| @@ -1112,13 +1269,14 @@ static int pn533_target_found(struct pn533 *dev, · 1 unmodified line | ||
| 1112 | 1269 | return rc; |
| 1113 | 1270 | |
| 1114 | 1271 | if (!(nfc_tgt.supported_protocols & dev->poll_protocols)) { |
| 1115 | − nfc_dev_dbg(&dev->interface->dev, "The target found does not" | |
| 1116 | − " have the desired protocol"); | |
| 1272 | + nfc_dev_dbg(&dev->interface->dev, | |
| 1273 | + "The Tg found doesn't have the desired protocol"); | |
| 1117 | 1274 | return -EAGAIN; |
| 1118 | 1275 | } |
| 1119 | 1276 | |
| 1120 | − nfc_dev_dbg(&dev->interface->dev, "Target found - supported protocols: " | |
| 1121 | − "0x%x", nfc_tgt.supported_protocols); | |
| 1277 | + nfc_dev_dbg(&dev->interface->dev, | |
| 1278 | + "Target found - supported protocols: 0x%x", | |
| 1279 | + nfc_tgt.supported_protocols); | |
| 1122 | 1280 | |
| 1123 | 1281 | dev->tgt_available_prots = nfc_tgt.supported_protocols; |
| 1124 | 1282 | |
| @@ -1140,7 +1298,7 @@ static void pn533_poll_reset_mod_list(struct pn533 *dev) · 15 unmodified lines | ||
| 1140 | 1298 | static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index) |
| 1141 | 1299 | { |
| 1142 | 1300 | dev->poll_mod_active[dev->poll_mod_count] = |
| 1143 | − (struct pn533_poll_modulations *) &poll_mod[mod_index]; | |
| 1301 | + (struct pn533_poll_modulations *)&poll_mod[mod_index]; | |
| 1144 | 1302 | dev->poll_mod_count++; |
| 1145 | 1303 | } |
| 1146 | 1304 | |
| @@ -1149,13 +1307,13 @@ static void pn533_poll_create_mod_list(struct pn533 *dev, · 2 unmodified lines | ||
| 1149 | 1307 | { |
| 1150 | 1308 | pn533_poll_reset_mod_list(dev); |
| 1151 | 1309 | |
| 1152 | − if (im_protocols & NFC_PROTO_MIFARE_MASK | |
| 1153 | − || im_protocols & NFC_PROTO_ISO14443_MASK | |
| 1154 | − || im_protocols & NFC_PROTO_NFC_DEP_MASK) | |
| 1310 | + if ((im_protocols & NFC_PROTO_MIFARE_MASK) || | |
| 1311 | + (im_protocols & NFC_PROTO_ISO14443_MASK) || | |
| 1312 | + (im_protocols & NFC_PROTO_NFC_DEP_MASK)) | |
| 1155 | 1313 | pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A); |
| 1156 | 1314 | |
| 1157 | − if (im_protocols & NFC_PROTO_FELICA_MASK | |
| 1158 | − || im_protocols & NFC_PROTO_NFC_DEP_MASK) { | |
| 1315 | + if (im_protocols & NFC_PROTO_FELICA_MASK || | |
| 1316 | + im_protocols & NFC_PROTO_NFC_DEP_MASK) { | |
| 1159 | 1317 | pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA); |
| 1160 | 1318 | pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA); |
| 1161 | 1319 | } |
| @@ -1170,16 +1328,20 @@ static void pn533_poll_create_mod_list(struct pn533 *dev, · 8 unmodified lines | ||
| 1170 | 1328 | pn533_poll_add_mod(dev, PN533_LISTEN_MOD); |
| 1171 | 1329 | } |
| 1172 | 1330 | |
| 1173 | −static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_len) | |
| 1331 | +static int pn533_start_poll_complete(struct pn533 *dev, struct sk_buff *resp) | |
| 1174 | 1332 | { |
| 1175 | − struct pn533_poll_response *resp; | |
| 1176 | − int rc; | |
| 1333 | + u8 nbtg, tg, *tgdata; | |
| 1334 | + int rc, tgdata_len; | |
| 1177 | 1335 | |
| 1178 | 1336 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
| 1179 | 1337 | |
| 1180 | − resp = (struct pn533_poll_response *) params; | |
| 1181 | − if (resp->nbtg) { | |
| 1182 | − rc = pn533_target_found(dev, resp, params_len); | |
| 1338 | + nbtg = resp->data[0]; | |
| 1339 | + tg = resp->data[1]; | |
| 1340 | + tgdata = &resp->data[2]; | |
| 1341 | + tgdata_len = resp->len - 2; /* nbtg + tg */ | |
| 1342 | + | |
| 1343 | + if (nbtg) { | |
| 1344 | + rc = pn533_target_found(dev, tg, tgdata, tgdata_len); | |
| 1183 | 1345 | |
| 1184 | 1346 | /* We must stop the poll after a valid target found */ |
| 1185 | 1347 | if (rc == 0) { |
| @@ -1191,158 +1353,134 @@ static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_l · 5 unmodified lines | ||
| 1191 | 1353 | return -EAGAIN; |
| 1192 | 1354 | } |
| 1193 | 1355 | |
| 1194 | −static int pn533_init_target_frame(struct pn533_frame *frame, | |
| 1195 | − u8 *gb, size_t gb_len) | |
| 1356 | +static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) | |
| 1196 | 1357 | { |
| 1197 | − struct pn533_cmd_init_target *cmd; | |
| 1198 | − size_t cmd_len; | |
| 1358 | + struct sk_buff *skb; | |
| 1359 | + u8 *felica, *nfcid3, *gb; | |
| 1360 | + | |
| 1361 | + u8 *gbytes = dev->gb; | |
| 1362 | + size_t gbytes_len = dev->gb_len; | |
| 1363 | + | |
| 1199 | 1364 | u8 felica_params[18] = {0x1, 0xfe, /* DEP */ |
| 1200 | 1365 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */ |
| 1201 | 1366 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
| 1202 | 1367 | 0xff, 0xff}; /* System code */ |
| 1368 | + | |
| 1203 | 1369 | u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */ |
| 1204 | 1370 | 0x0, 0x0, 0x0, |
| 1205 | 1371 | 0x40}; /* SEL_RES for DEP */ |
| 1206 | 1372 | |
| 1207 | − cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1; | |
| 1208 | − cmd = kzalloc(cmd_len, GFP_KERNEL); | |
| 1209 | − if (cmd == NULL) | |
| 1210 | − return -ENOMEM; | |
| 1373 | + unsigned int skb_len = 36 + /* mode (1), mifare (6), | |
| 1374 | + felica (18), nfcid3 (10), gb_len (1) */ | |
| 1375 | + gbytes_len + | |
| 1376 | + 1; /* len Tk*/ | |
| 1211 | 1377 | |
| 1212 | − pn533_tx_frame_init(frame, PN533_CMD_TG_INIT_AS_TARGET); | |
| 1378 | + skb = pn533_alloc_skb(dev, skb_len); | |
| 1379 | + if (!skb) | |
| 1380 | + return NULL; | |
| 1213 | 1381 | |
| 1214 | 1382 | /* DEP support only */ |
| 1215 | − cmd->mode |= PN533_INIT_TARGET_DEP; | |
| 1383 | + *skb_put(skb, 1) |= PN533_INIT_TARGET_DEP; | |
| 1384 | + | |
| 1385 | + /* MIFARE params */ | |
| 1386 | + memcpy(skb_put(skb, 6), mifare_params, 6); | |
| 1216 | 1387 | |
| 1217 | 1388 | /* Felica params */ |
| 1218 | − memcpy(cmd->felica, felica_params, 18); | |
| 1219 | − get_random_bytes(cmd->felica + 2, 6); | |
| 1389 | + felica = skb_put(skb, 18); | |
| 1390 | + memcpy(felica, felica_params, 18); | |
| 1391 | + get_random_bytes(felica + 2, 6); | |
| 1220 | 1392 | |
| 1221 | 1393 | /* NFCID3 */ |
| 1222 | − memset(cmd->nfcid3, 0, 10); | |
| 1223 | − memcpy(cmd->nfcid3, cmd->felica, 8); | |
| 1224 | − | |
| 1225 | − /* MIFARE params */ | |
| 1226 | − memcpy(cmd->mifare, mifare_params, 6); | |
| 1394 | + nfcid3 = skb_put(skb, 10); | |
| 1395 | + memset(nfcid3, 0, 10); | |
| 1396 | + memcpy(nfcid3, felica, 8); | |
| 1227 | 1397 | |
| 1228 | 1398 | /* General bytes */ |
| 1229 | − cmd->gb_len = gb_len; | |
| 1230 | − memcpy(cmd->gb, gb, gb_len); | |
| 1231 | − | |
| 1232 | − /* Len Tk */ | |
| 1233 | − cmd->gb[gb_len] = 0; | |
| 1234 | − | |
| 1235 | − memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len); | |
| 1399 | + *skb_put(skb, 1) = gbytes_len; | |
| 1236 | 1400 | |
| 1237 | − frame->datalen += cmd_len; | |
| 1401 | + gb = skb_put(skb, gbytes_len); | |
| 1402 | + memcpy(gb, gbytes, gbytes_len); | |
| 1238 | 1403 | |
| 1239 | − pn533_tx_frame_finish(frame); | |
| 1240 | − | |
| 1241 | − kfree(cmd); | |
| 1404 | + /* Len Tk */ | |
| 1405 | + *skb_put(skb, 1) = 0; | |
| 1242 | 1406 | |
| 1243 | − return 0; | |
| 1407 | + return skb; | |
| 1244 | 1408 | } |
| 1245 | 1409 | |
| 1246 | −#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3) | |
| 1410 | +#define PN533_CMD_DATAEXCH_HEAD_LEN 1 | |
| 1247 | 1411 | #define PN533_CMD_DATAEXCH_DATA_MAXLEN 262 |
| 1248 | 1412 | static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg, |
| 1249 | − u8 *params, int params_len) | |
| 1413 | + struct sk_buff *resp) | |
| 1250 | 1414 | { |
| 1251 | − struct sk_buff *skb_resp = arg; | |
| 1252 | − struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data; | |
| 1415 | + u8 status; | |
| 1253 | 1416 | |
| 1254 | 1417 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
| 1255 | 1418 | |
| 1256 | − if (params_len < 0) { | |
| 1257 | − nfc_dev_err(&dev->interface->dev, | |
| 1258 | − "Error %d when starting as a target", | |
| 1259 | − params_len); | |
| 1419 | + if (IS_ERR(resp)) | |
| 1420 | + return PTR_ERR(resp); | |
| 1260 | 1421 | |
| 1261 | − return params_len; | |
| 1262 | − } | |
| 1422 | + status = resp->data[0]; | |
| 1423 | + skb_pull(resp, sizeof(status)); | |
| 1263 | 1424 | |
| 1264 | − if (params_len > 0 && params[0] != 0) { | |
| 1425 | + if (status != 0) { | |
| 1265 | 1426 | nfc_tm_deactivated(dev->nfc_dev); |
| 1266 | − | |
| 1267 | 1427 | dev->tgt_mode = 0; |
| 1268 | − | |
| 1269 | − kfree_skb(skb_resp); | |
| 1428 | + dev_kfree_skb(resp); | |
| 1270 | 1429 | return 0; |
| 1271 | 1430 | } |
| 1272 | 1431 | |
| 1273 | − skb_put(skb_resp, PN533_FRAME_SIZE(in_frame)); | |
| 1274 | − skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN); | |
| 1275 | − skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE); | |
| 1276 | − | |
| 1277 | − return nfc_tm_data_received(dev->nfc_dev, skb_resp); | |
| 1432 | + return nfc_tm_data_received(dev->nfc_dev, resp); | |
| 1278 | 1433 | } |
| 1279 | 1434 | |
| 1280 | 1435 | static void pn533_wq_tg_get_data(struct work_struct *work) |
| 1281 | 1436 | { |
| 1282 | 1437 | struct pn533 *dev = container_of(work, struct pn533, tg_work); |
| 1283 | − struct pn533_frame *in_frame; | |
| 1284 | − struct sk_buff *skb_resp; | |
| 1285 | − size_t skb_resp_len; | |
| 1286 | 1438 | |
| 1287 | − nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | |
| 1439 | + struct sk_buff *skb; | |
| 1440 | + int rc; | |
| 1288 | 1441 | |
| 1289 | − skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN + | |
| 1290 | − PN533_CMD_DATAEXCH_DATA_MAXLEN + | |
| 1291 | − PN533_FRAME_TAIL_SIZE; | |
| 1442 | + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | |
| 1292 | 1443 | |
| 1293 | − skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL); | |
| 1294 | − if (!skb_resp) | |
| 1444 | + skb = pn533_alloc_skb(dev, 0); | |
| 1445 | + if (!skb) | |
| 1295 | 1446 | return; |
| 1296 | 1447 | |
| 1297 | − in_frame = (struct pn533_frame *)skb_resp->data; | |
| 1448 | + rc = pn533_send_data_async(dev, PN533_CMD_TG_GET_DATA, skb, | |
| 1449 | + pn533_tm_get_data_complete, NULL); | |
| 1298 | 1450 | |
| 1299 | − pn533_tx_frame_init(dev->out_frame, PN533_CMD_TG_GET_DATA); | |
| 1300 | − pn533_tx_frame_finish(dev->out_frame); | |
| 1301 | − | |
| 1302 | − pn533_send_cmd_frame_async(dev, dev->out_frame, in_frame, | |
| 1303 | − skb_resp_len, | |
| 1304 | − pn533_tm_get_data_complete, | |
| 1305 | − skb_resp, GFP_KERNEL); | |
| 1451 | + if (rc < 0) | |
| 1452 | + dev_kfree_skb(skb); | |
| 1306 | 1453 | |
| 1307 | 1454 | return; |
| 1308 | 1455 | } |
| 1309 | 1456 | |
| 1310 | 1457 | #define ATR_REQ_GB_OFFSET 17 |
| 1311 | −static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_len) | |
| 1458 | +static int pn533_init_target_complete(struct pn533 *dev, struct sk_buff *resp) | |
| 1312 | 1459 | { |
| 1313 | − struct pn533_cmd_init_target_response *resp; | |
| 1314 | − u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb; | |
| 1460 | + u8 mode, *cmd, comm_mode = NFC_COMM_PASSIVE, *gb; | |
| 1315 | 1461 | size_t gb_len; |
| 1316 | 1462 | int rc; |
| 1317 | 1463 | |
| 1318 | 1464 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
| 1319 | 1465 | |
| 1320 | − if (params_len < 0) { | |
| 1321 | − nfc_dev_err(&dev->interface->dev, | |
| 1322 | − "Error %d when starting as a target", | |
| 1323 | − params_len); | |
| 1324 | − | |
| 1325 | − return params_len; | |
| 1326 | − } | |
| 1327 | − | |
| 1328 | − if (params_len < ATR_REQ_GB_OFFSET + 1) | |
| 1466 | + if (resp->len < ATR_REQ_GB_OFFSET + 1) | |
| 1329 | 1467 | return -EINVAL; |
| 1330 | 1468 | |
| 1331 | − resp = (struct pn533_cmd_init_target_response *) params; | |
| 1469 | + mode = resp->data[0]; | |
| 1470 | + cmd = &resp->data[1]; | |
| 1332 | 1471 | |
| 1333 | − nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x param len %d\n", | |
| 1334 | − resp->mode, params_len); | |
| 1472 | + nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x len %d\n", | |
| 1473 | + mode, resp->len); | |
| 1335 | 1474 | |
1210 more lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.